1
- import loop from ' ./loop' ;
2
- import { select , append , attr , style , text } from ' ./selection' ;
3
- import transition from ' ./transition' ;
1
+ import loop from " ./loop" ;
2
+ import { select , append , attr , style , text } from " ./selection" ;
3
+ import transition from " ./transition" ;
4
4
5
5
const DIGITS_COUNT = 10 ;
6
6
const ROTATIONS = 3 ;
7
7
8
8
const createDigitRoulette = ( svg , fontSize , lineHeight , id ) => {
9
9
const digits = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ] ;
10
10
const roulette = svg
11
- ::append ( 'g' )
12
- ::attr ( 'id' , `digit-${ id } ` )
13
- ::style ( ' filter' , `url(#motionFilter-${ id } )` ) ;
11
+ ::append ( "g" )
12
+ ::attr ( "id" , `digit-${ id } ` )
13
+ ::style ( " filter" , `url(#motionFilter-${ id } )` ) ;
14
14
15
15
digits . forEach ( ( el , i ) => {
16
16
roulette
17
- ::append ( ' text' )
18
- ::attr ( 'y' , - i * fontSize * lineHeight )
17
+ ::append ( " text" )
18
+ ::attr ( "y" , - i * fontSize * lineHeight )
19
19
::text ( el ) ;
20
20
} ) ;
21
21
22
22
return roulette ;
23
23
} ;
24
24
25
25
const createCharacter = ( svg , el , fontSize ) =>
26
- svg
27
- ::append ( 'g' )
28
- ::append ( 'text' )
29
- ::text ( el ) ;
26
+ svg ::append ( "g" ) ::append ( "text" ) ::text ( el ) ;
30
27
31
28
const createFilter = ( defs , id ) =>
32
29
defs
33
- ::append ( ' filter' )
34
- ::attr ( 'id' , `motionFilter-${ id } ` )
35
- ::attr ( ' width' , ' 300%' )
36
- ::attr ( 'x' , ' -100%' )
37
- ::append ( ' feGaussianBlur' )
38
- ::attr ( ' class' , ' blurValues' )
39
- ::attr ( 'in' , ' SourceGraphic' )
40
- ::attr ( ' stdDeviation' , ' 0 0' ) ;
30
+ ::append ( " filter" )
31
+ ::attr ( "id" , `motionFilter-${ id } ` )
32
+ ::attr ( " width" , " 300%" )
33
+ ::attr ( "x" , " -100%" )
34
+ ::append ( " feGaussianBlur" )
35
+ ::attr ( " class" , " blurValues" )
36
+ ::attr ( "in" , " SourceGraphic" )
37
+ ::attr ( " stdDeviation" , " 0 0" ) ;
41
38
42
39
const createGradient = ( defs , id ) =>
43
40
defs
44
- ::append ( ' linearGradient' )
45
- ::attr ( 'id' , `gradient-${ id } ` )
46
- ::attr ( 'x1' , '0%' )
47
- ::attr ( 'y1' , '0%' )
48
- ::attr ( 'x2' , '0%' )
49
- ::attr ( 'y2' , ' 100%' )
50
- ::append ( ' stop' )
51
- ::attr ( ' offset' , '0' )
52
- ::attr ( ' stop-color' , ' white' )
53
- ::attr ( ' stop-opacity' , '0' )
41
+ ::append ( " linearGradient" )
42
+ ::attr ( "id" , `gradient-${ id } ` )
43
+ ::attr ( "x1" , "0%" )
44
+ ::attr ( "y1" , "0%" )
45
+ ::attr ( "x2" , "0%" )
46
+ ::attr ( "y2" , " 100%" )
47
+ ::append ( " stop" )
48
+ ::attr ( " offset" , "0" )
49
+ ::attr ( " stop-color" , " white" )
50
+ ::attr ( " stop-opacity" , "0" )
54
51
::select ( `#gradient-${ id } ` )
55
- ::append ( ' stop' )
56
- ::attr ( ' offset' , ' 0.2' )
57
- ::attr ( ' stop-color' , ' white' )
58
- ::attr ( ' stop-opacity' , '1' )
52
+ ::append ( " stop" )
53
+ ::attr ( " offset" , " 0.2" )
54
+ ::attr ( " stop-color" , " white" )
55
+ ::attr ( " stop-opacity" , "1" )
59
56
::select ( `#gradient-${ id } ` )
60
- ::append ( ' stop' )
61
- ::attr ( ' offset' , ' 0.8' )
62
- ::attr ( ' stop-color' , ' white' )
63
- ::attr ( ' stop-opacity' , '1' )
57
+ ::append ( " stop" )
58
+ ::attr ( " offset" , " 0.8" )
59
+ ::attr ( " stop-color" , " white" )
60
+ ::attr ( " stop-opacity" , "1" )
64
61
::select ( `#gradient-${ id } ` )
65
- ::append ( ' stop' )
66
- ::attr ( ' offset' , '1' )
67
- ::attr ( ' stop-color' , ' white' )
68
- ::attr ( ' stop-opacity' , '0' ) ;
62
+ ::append ( " stop" )
63
+ ::attr ( " offset" , "1" )
64
+ ::attr ( " stop-color" , " white" )
65
+ ::attr ( " stop-opacity" , "0" ) ;
69
66
70
67
const createMask = ( defs , id ) =>
71
68
defs
72
- ::append ( ' mask' )
73
- ::attr ( 'id' , `mask-${ id } ` )
74
- ::append ( ' rect' )
75
- ::attr ( 'x' , 0 )
76
- ::attr ( 'y' , 0 )
77
- ::attr ( ' width' , ' 100%' )
78
- ::attr ( ' height' , ' 100%' )
79
- ::attr ( ' fill' , `url(#gradient-${ id } )` ) ;
69
+ ::append ( " mask" )
70
+ ::attr ( "id" , `mask-${ id } ` )
71
+ ::append ( " rect" )
72
+ ::attr ( "x" , 0 )
73
+ ::attr ( "y" , 0 )
74
+ ::attr ( " width" , " 100%" )
75
+ ::attr ( " height" , " 100%" )
76
+ ::attr ( " fill" , `url(#gradient-${ id } )` ) ;
80
77
81
78
const setViewBox = ( svg , width , height ) => {
82
- svg::attr ( ' width' , width ) ;
83
- svg::attr ( ' height' , height ) ;
84
- svg::attr ( ' viewBox' , `0 0 ${ width } ${ height } ` ) ;
85
- svg::style ( ' overflow' , ' hidden' ) ;
79
+ svg::attr ( " width" , width ) ;
80
+ svg::attr ( " height" , height ) ;
81
+ svg::attr ( " viewBox" , `0 0 ${ width } ${ height } ` ) ;
82
+ svg::style ( " overflow" , " hidden" ) ;
86
83
} ;
87
84
88
85
export default ( {
@@ -93,7 +90,7 @@ export default ({
93
90
letterSpacing = 1 ,
94
91
animationDelay = 100 ,
95
92
letterAnimationDelay = 100 ,
96
- duration = 3000
93
+ duration = 3000 ,
97
94
} ) => {
98
95
const element = select ( el ) ;
99
96
const computedStyle = window . getComputedStyle ( element ) ;
@@ -105,28 +102,26 @@ export default ({
105
102
let canvasWidth = 0 ;
106
103
const canvasHeight = fontSize * lineHeight + marginBottom ;
107
104
108
- element . innerHTML = '' ;
109
- const root = element ::append ( ' svg' ) ;
110
- const svg = root ::append ( ' svg' ) ::attr ( ' mask' , `url(#mask-${ salt } )` ) ;
111
- const defs = root ::append ( ' defs' ) ;
105
+ element . innerHTML = "" ;
106
+ const root = element ::append ( " svg" ) ;
107
+ const svg = root ::append ( " svg" ) ::attr ( " mask" , `url(#mask-${ salt } )` ) ;
108
+ const defs = root ::append ( " defs" ) ;
112
109
createGradient ( defs , salt ) ;
113
110
createMask ( defs , salt ) ;
114
111
115
112
const prepareValues = ( value , secondValue ) => {
116
- const values = String ( value )
117
- . replace ( / / g, '\u00a0' )
118
- . split ( '' ) ;
113
+ const values = String ( value ) . replace ( / / g, "\u00a0" ) . split ( "" ) ;
119
114
120
115
const digitIndex = String ( value ) . search ( / \d / ) ;
121
116
while ( secondValue . length > values . length ) {
122
117
const char =
123
118
secondValue [ secondValue . length - values . length - 1 + digitIndex ] ;
124
- values . splice ( digitIndex , 0 , isNaN ( parseInt ( char , 10 ) ) ? char : '0' ) ;
119
+ values . splice ( digitIndex , 0 , isNaN ( parseInt ( char , 10 ) ) ? char : "0" ) ;
125
120
}
126
121
return values ;
127
122
} ;
128
123
129
- const initialString = String ( initialValue || '0' ) ;
124
+ const initialString = String ( initialValue || "0" ) ;
130
125
const values = prepareValues ( String ( value ) , initialString ) ;
131
126
const initial = prepareValues ( initialString , String ( value ) ) ;
132
127
@@ -137,7 +132,7 @@ export default ({
137
132
isDigit : false ,
138
133
node : createCharacter ( svg , char , fontSize ) ,
139
134
value : char ,
140
- offset : { x : 0 , y : offset }
135
+ offset : { x : 0 , y : offset } ,
141
136
} ;
142
137
} else {
143
138
return {
@@ -149,14 +144,14 @@ export default ({
149
144
initial : Number ( initial [ i ] ) ,
150
145
offset : {
151
146
x : 0 ,
152
- y : offset + Number ( initial [ i ] ) * ( fontSize * lineHeight )
153
- }
147
+ y : offset + Number ( initial [ i ] ) * ( fontSize * lineHeight ) ,
148
+ } ,
154
149
} ;
155
150
}
156
151
} ) ;
157
152
158
153
const transitions = [ ] ;
159
- const digits = chars . filter ( char => char . isDigit ) ;
154
+ const digits = chars . filter ( ( char ) => char . isDigit ) ;
160
155
digits . forEach ( ( digit , i ) => {
161
156
const sourceDistance = digit . initial * ( fontSize * lineHeight ) ;
162
157
const targetDistance =
@@ -170,7 +165,7 @@ export default ({
170
165
digit . offset . y =
171
166
offset + ( value % ( fontSize * lineHeight * DIGITS_COUNT ) ) ;
172
167
digit . node ::attr (
173
- ' transform' ,
168
+ " transform" ,
174
169
`translate(${ digit . offset . x } , ${ digit . offset . y } )`
175
170
) ;
176
171
const filterOrigin = ( sourceDistance + targetDistance ) / 2 ;
@@ -180,48 +175,59 @@ export default ({
180
175
sourceDistance
181
176
) / 100
182
177
) . toFixed ( 1 ) ;
183
- digit . filter ::attr ( ' stdDeviation' , `0 ${ motionValue } ` ) ;
178
+ digit . filter ::attr ( " stdDeviation" , `0 ${ motionValue } ` ) ;
184
179
} ,
185
- end : i === 0 ? ( ) => {
186
- element . querySelectorAll ( '[style*="filter"]' ) . forEach ( ele => {
187
- ele . style . filter = ''
188
- } ) ;
189
- cancelAnimation ( ) ;
190
- } : e => e
180
+ end :
181
+ i === 0
182
+ ? ( ) => {
183
+ element . querySelectorAll ( '[style*="filter"]' ) . forEach ( ( ele ) => {
184
+ ele . style . filter = "" ;
185
+ } ) ;
186
+ cancel ( ) ;
187
+ }
188
+ : ( e ) => e ,
191
189
} ) ;
192
190
transitions . push ( digitTransition ) ;
193
191
} ) ;
194
192
195
- const update = timestamp => {
193
+ const update = ( timestamp ) => {
196
194
canvasWidth = 0 ;
197
- chars . forEach ( char => {
195
+ chars . forEach ( ( char ) => {
198
196
const { width } = char . node . getBBox ( ) ;
199
197
200
198
char . offset . x = canvasWidth ;
201
199
// set proper kerning for proportional fonts
202
200
if ( char . isDigit ) {
203
- [ ...char . node . childNodes ] . forEach ( element => {
201
+ [ ...char . node . childNodes ] . forEach ( ( element ) => {
204
202
const { width : letterWidth } = element . getBBox ( ) ;
205
203
const offset = ( width - letterWidth ) / 2 ;
206
- element . setAttribute ( 'x' , offset ) ;
204
+ element . setAttribute ( "x" , offset ) ;
207
205
} ) ;
208
206
}
209
207
210
208
canvasWidth += width + letterSpacing ;
211
209
} ) ;
212
210
canvasWidth -= letterSpacing ;
213
211
214
- chars . forEach ( char => {
212
+ chars . forEach ( ( char ) => {
215
213
char . node ::attr (
216
- ' transform' ,
214
+ " transform" ,
217
215
`translate(${ char . offset . x } , ${ char . offset . y } )`
218
216
) ;
219
217
} ) ;
220
218
221
219
setViewBox ( root , canvasWidth , canvasHeight ) ;
222
- transitions . forEach ( transition => transition . update ( timestamp ) ) ;
220
+ transitions . forEach ( ( transition ) => transition . update ( timestamp ) ) ;
221
+ } ;
222
+
223
+ const cancel = loop ( update ) ;
224
+
225
+ const pause = ( ) => {
226
+ transitions . forEach ( ( transition ) => transition . pause ( ) ) ;
227
+ } ;
228
+ const resume = ( ) => {
229
+ transitions . forEach ( ( transition ) => transition . resume ( ) ) ;
223
230
} ;
224
231
225
- const cancelAnimation = loop ( update ) ;
226
- return cancelAnimation ;
232
+ return { cancel, pause, resume } ;
227
233
} ;
0 commit comments