-
Notifications
You must be signed in to change notification settings - Fork 16
/
ShuffleText.ts
150 lines (132 loc) · 3.82 KB
/
ShuffleText.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* ShuffleText is random text effect class for DOM Elements.
* ShuffleTextはDOMエレメント用ランダムテキストクラスです。
* @author Yasunobu Ikeda
* @since 2012-02-07
*/
export default class ShuffleText {
/**
* The string for random text.
* ランダムテキストに用いる文字列です。
* @type {string}
* @default 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
*/
public sourceRandomCharacter: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
/**
* The string for effect space.
* 空白に用いる文字列です。
* @type {string}
* @default '-'
*/
public emptyCharacter: string = "-";
/**
* The milli seconds of effect time.
* エフェクトの実行時間(ミリ秒)です。
* @type {number}
* @default 600
*/
public duration: number = 600;
private _isRunning: boolean = false;
private _originalStr: string = "";
private _originalLength: number = 0;
private _timeCurrent: number = 0;
private _timeStart: number = 0;
private _randomIndex: number[] = [];
private _element: HTMLElement | null = null;
private _requestAnimationFrameId: number = 0;
/**
* Constructor.
* @param element DOMエレメントです。
*/
constructor(element: HTMLElement) {
this._element = element;
this.setText(element.textContent ?? "");
}
/**
* Set new strings. テキストを設定します。
* @param text テキスト文字列です。
*/
public setText(text: string): void {
this._originalStr = text;
this._originalLength = text.length;
}
/**
* It is running flag. 再生中かどうかを示すブール値です。
* @returns {boolean}
*/
public get isRunning(): boolean {
return this._isRunning;
}
/** Play effect. 再生を開始します。 */
public start(): void {
this.stop();
this._randomIndex = [];
let str = "";
for (let i = 0; i < this._originalLength; i++) {
let rate = i / this._originalLength;
this._randomIndex[i] = Math.random() * (1 - rate) + rate;
str += this.emptyCharacter;
}
this._timeStart = new Date().getTime();
this._isRunning = true;
this._requestAnimationFrameId = requestAnimationFrame(() => {
this._onInterval();
});
if (this._element) {
this._element.textContent = str;
}
}
/** Stop effect. 停止します。 */
public stop(): void {
this._isRunning = false;
cancelAnimationFrame(this._requestAnimationFrameId);
}
/**
* Dispose this instance.
* メモリ解放のためインスタンスを破棄します。
*/
public dispose(): void {
cancelAnimationFrame(this._requestAnimationFrameId);
this._isRunning = false;
this.duration = 0;
this._originalStr = "";
this._originalLength = 0;
this._timeCurrent = 0;
this._timeStart = 0;
this._randomIndex = [];
this._element = null;
this._requestAnimationFrameId = 0;
}
/**
* インターバルハンドラーです。
* @private
*/
private _onInterval(): void {
this._timeCurrent = new Date().getTime() - this._timeStart;
const percent = this._timeCurrent / this.duration;
let str = "";
for (let i = 0; i < this._originalLength; i++) {
if (percent >= this._randomIndex[i]) {
str += this._originalStr.charAt(i);
} else if (percent < this._randomIndex[i] / 3) {
str += this.emptyCharacter;
} else {
str += this.sourceRandomCharacter.charAt(
Math.floor(Math.random() * this.sourceRandomCharacter.length)
);
}
}
if (percent > 1) {
str = this._originalStr;
this._isRunning = false;
}
if (this._element) {
this._element.textContent = str;
}
if (this._isRunning) {
this._requestAnimationFrameId = requestAnimationFrame(() => {
this._onInterval();
});
}
}
}