把之前在cocoscreator里面滚动字,在laya中再实现下。
使用方法:
this.label.text = 0; //laya label 控件
let scrollLabel = this.label.addComponent(ScrollLabelComponent);
scrollLabel.setValue(100);
ScrollLabelComonent.ts 代码
//滚动label 控件
/**
* 引用github仓库
* https://github.com/inorganik/countUp.js/edit/master/dist/countUp.js
* version = '2.0.7'
*/
/*
// Object 现在存在 __assign方法 若不存添加这个方法
let __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
*/
/*
默认参数
*/
let defaultOptions = {
startVal: 0, // 开始值;
duration: 2, // 滚动持续时间;
useGrouping: true, // 千分位效果,例:1000->1,000。默认true
separator: ',', // 使用千分位时分割符号
decimal: '.', // 小数位分割符号
decimalPlaces: 2, // 小数后几位
prefix: '', // 前置符号
suffix: '', // 后置符号,可汉字
smartEasingThreshold: 999,
smartEasingAmount: 333,
useEasing: true, // 过渡动画效果,默认ture
// numerals: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], //可定制;
//easingFn, // easing函数 可定制
//formattingFn, // 序列话数值函数 可定制
};
let easingOutQuintic = function (t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc * ts + -5 * ts * ts + 10 * tc + -10 * ts + 5 * t);
}
let easingOutCubic = function (t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc + -3 * ts + 3 * t);
}
let easingOutExpo = function (t, b, c, d) {
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
};
let easingInExpo = function (t, b, c, d) {
return c * (Math.pow(2, 10 * (t / d - 1))) * 1024 / 1023 + b;
};
export default class LabelComponent extends Laya.Script {
public options;
public endValue;
public startValue;
public finalEndValue;
public useEasing;
public countDown;
public error;
public paused;
public startTime;
public formattingFn;
public easingFn;
public frameValue;
public rAF;
public duration;
public callback;
public remaining;
constructor() {
super();
}
onAwake() {
this.options = defaultOptions;
this.endValue = 0;
this.startValue = 0;
this.finalEndValue = null;
this.useEasing = true;
this.countDown = false;
this.error = '';
this.paused = true;
this.init();
}
onEnable(): void {
}
onDisable(): void {
}
onDestroy(): void {
}
onUpdate(): void {
}
public init(): void {
this.formattingFn = (typeof this.options.formattingFn == 'function') ? this.options.formattingFn : this.formatNumber;
this.easingFn = (typeof this.options.easingFn == 'function') ? this.options.easingFn : easingInExpo;
this.startValue = this.validateValue(this.options.startVal);
this.frameValue = this.startValue;
this.options.decimalPlaces = Math.max(0 || this.options.decimalPlaces);
this.options.separator = String(this.options.separator);
this.useEasing = this.options.useEasing;
if (this.options.separator === '') {
this.options.useGrouping = false;
}
this.resetDuration();
this.printValue(this.startValue);
}
/**
* 设置选项
* @param {obj} options
*/
public setOptions(options) {
this.options = Object.assign(Object.assign({}, defaultOptions), options);
}
/**
* 设置结束数值
* @param {number} value
* @param {function} callback
*/
public setValue(value, callback) {
if (this.options) {
this.options.startVal = Number((this.owner as Laya.Label).text.replace(/,/g, '')) || 0;
}
this.endValue = value;
this.init();
this.startScroll(callback);
}
/**
* 重置开始数值
* @param {number} value
*/
public resetValue(value = 0) {
cancelAnimationFrame(this.rAF);
this.paused = true;
this.resetDuration();
this.options.startVal = value;
this.startValue = this.validateValue(value);
this.frameValue = this.startValue;
this.printValue(this.startValue);
}
/**
* 决定方向和easing函数
*/
public determineDirectionAndSmartEasing() {
let value = (this.finalEndValue) ? this.finalEndValue : this.endValue;
this.countDown = (this.startValue > value);
let animateAmount = value - this.startValue;
if (Math.abs(animateAmount) > this.options.smartEasingThreshold) {
this.finalEndValue = value;
let up = (this.countDown) ? 1 : -1;
this.endValue = value + (up * this.options.smartEasingAmount);
this.duration = this.duration / 2;
} else {
this.endValue = value;
this.finalEndValue = null;
}
if (this.finalEndValue) {
this.useEasing = false;
} else {
this.useEasing = this.options.useEasing;
}
}
public startScroll(callback) {
if (this.error) {
return;
}
this.callback = callback;
if (this.duration > 0) {
this.determineDirectionAndSmartEasing();
this.paused = false;
this.rAF = requestAnimationFrame(this.count.bind(this));
} else {
this.printValue(this.endValue);
}
}
/**
* 暂停恢复
*/
public pauseResume() {
if (!this.paused) {
cancelAnimationFrame(this.rAF);
} else {
this.startTime = null;
this.duration = this.remaining;
this.startValue = this.frameValue;
this.determineDirectionAndSmartEasing();
this.rAF = requestAnimationFrame(this.count.bind(this));
}
this.paused = !this.paused;
}
/**
* 恢复
*/
public pause() {
cancelAnimationFrame(this.rAF);
this.paused = true;
}
/**
* 恢复
*/
public resume() {
this.startTime = null;
this.duration = this.remaining;
this.startValue = this.frameValue;
this.determineDirectionAndSmartEasing();
this.rAF = requestAnimationFrame(this.count.bind(this));
this.paused = false;
}
/**
* 更新到最后的数值
* @param {number} newEndVal
*/
public updateFinalEndValue(newEndVal) {
cancelAnimationFrame(this.rAF);
this.startTime = null;
this.endValue = this.validateValue(newEndVal);
if (this.endValue === this.frameValue) {
return;
}
this.startValue = this.frameValue;
if (!this.finalEndValue) {
this.resetDuration();
}
this.finalEndValue = null;
this.determineDirectionAndSmartEasing();
this.rAF = requestAnimationFrame(this.count.bind(this));
}
/**
* 每帧去计算
* @param {number} timestamp
*/
public count(timestamp) {
if (!this.startTime) {
this.startTime = timestamp;
}
let progress = timestamp - this.startTime;
this.remaining = this.duration - progress;
if (this.useEasing) {
if (this.countDown) {
this.frameValue = this.startValue - this.easingFn(progress, 0, this.startValue - this.endValue, this.duration);
} else {
this.frameValue = this.easingFn(progress, this.startValue, this.endValue - this.startValue, this.duration);
}
} else {
if (this.countDown) {
this.frameValue = this.startValue - ((this.startValue - this.endValue) * (progress / this.duration));
} else {
this.frameValue = this.startValue + (this.endValue - this.startValue) * (progress / this.duration);
}
}
// don't go past endValue since progress can exceed duration in the last frame
if (this.countDown) {
this.frameValue = (this.frameValue < this.endValue) ? this.endValue : this.frameValue;
} else {
this.frameValue = (this.frameValue > this.endValue) ? this.endValue : this.frameValue;
}
// decimal
this.frameValue = Number(this.frameValue.toFixed(this.options.decimalPlaces));
// format and print value
this.printValue(this.frameValue);
// whether to continue
if (progress < this.duration) {
this.rAF = requestAnimationFrame(this.count.bind(this));
} else if (this.finalEndValue !== null) {
// smart easing
this.updateFinalEndValue(this.finalEndValue);
} else {
if (this.callback) {
this.callback();
}
}
}
/**
* 千分位转换函数
* @param {number} num
*/
public formatNumber(num) {
let neg = (num < 0) ? '-' : '';
let result, x, x1, x2, x3;
result = Math.abs(num).toFixed(this.options.decimalPlaces);
if (result.indexOf(".") > 0) {
result = result.replace(/0+?$/, ''); //去掉后面无用的零
result = result.replace(/[.]$/, ''); //如小数点后面全是零则去掉小数点
}
result += '';
x = result.split('.');
x1 = x[0];
x2 = x.length > 1 ? this.options.decimal + x[1] : '';
if (this.options.useGrouping) {
x3 = '';
for (let i = 0, len = x1.length; i < len; ++i) {
if (i !== 0 && (i % 3) === 0) {
x3 = this.options.separator + x3;
}
x3 = x1[len - i - 1] + x3;
}
x1 = x3;
}
// optional numeral substitution
if (this.options.numerals && this.options.numerals.length) {
x1 = x1.replace(/[0-9]/g, function (w) {
return this.options.numerals[+w];
});
x2 = x2.replace(/[0-9]/g, function (w) {
return this.options.numerals[+w];
});
}
return neg + this.options.prefix + x1 + x2 + this.options.suffix;
}
/**
* 千分位转换
* @param {number} value
* @param {number} decimal
* @param {boolean} notDeleteZore
*/
public formatNumber2(value, decimal = 2, notDeleteZore = false) {
// value = 990009990900000;
let ret = (value / 100).toFixed(decimal).toString();
ret = '' + decimal ? ret.replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : ret.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
if (!notDeleteZore) {
if (ret.indexOf(".") > 0) {
ret = ret.replace(/0+?$/, ''); //去掉后面无用的零
ret = ret.replace(/[.]$/, ''); //如小数点后面全是零则去掉小数点
}
}
return ret;
}
/**
* 赋值输出
* @param {number} value
*/
public printValue(value) {
var result = this.formattingFn(value);
(this.owner as Laya.Label).text = "" + result;
console.log('[' + this.owner.name + ']' + " print value: " + value + ' format number: ' + result);
}
/**
* 确认是number类型
* @param {number} value
*/
public ensureNumber(value) {
return (typeof value === 'number' && !isNaN(value));
}
/**
* 验证数值
* @param {number} value
*/
public validateValue(value) {
var newValue = Number(value);
if (!this.ensureNumber(newValue)) {
this.error = "[CountUp] invalid start or end value: " + value;
return null;
} else {
return newValue;
}
}
/**
* 重置时间
*/
public resetDuration() {
this.startTime = null;
this.duration = Number(this.options.duration) * 1000;
this.remaining = this.duration;
}
}