@@ -2,6 +2,9 @@ import React, { Component, PropTypes } from 'react';
2
2
import { StyleSheet , css } from 'aphrodite/no-important' ;
3
3
4
4
const baseStyles = {
5
+ transition : {
6
+ transition : 'all 222ms ease-out' ,
7
+ } ,
5
8
layers : {
6
9
width : '100%' ,
7
10
height : '100%' ,
@@ -14,42 +17,29 @@ const baseStyles = {
14
17
} ;
15
18
16
19
const styles = StyleSheet . create ( {
17
- outter : {
18
- transformStyle : 'preserve-3d'
19
- } ,
20
- wrapper : {
20
+ parallaxHover__outter : {
21
+ transformStyle : 'preserve-3d' ,
21
22
position : 'relative' ,
22
- margin : 0 ,
23
- padding : 0 ,
24
- transition : 'all 180ms ease-in-out' ,
23
+ overflow : 'visible' ,
24
+ ...baseStyles . transition ,
25
25
} ,
26
- shadow : {
27
- background : 'rgba(0, 0, 0, 0.2) ' ,
26
+ parallaxHover__wrapper : {
27
+ overflow : 'hidden ' ,
28
28
...baseStyles . layers ,
29
- filter : 'blur(3px)' ,
29
+ } ,
30
+ parallaxHover__shadow : {
31
+ position : 'absolute' ,
30
32
width : '80%' ,
31
33
height : '80%' ,
32
34
left : '10%' ,
33
35
top : '10%' ,
34
- transition : 'all 180ms ease-in-out' ,
35
- } ,
36
- layers : {
37
- ...baseStyles . layers
38
36
} ,
39
- layer : {
40
- ...baseStyles . layers ,
37
+ parallaxHover__layer : {
41
38
overflow : 'hidden' ,
42
- } ,
43
- lighting : {
44
- opacity : 0 ,
45
39
...baseStyles . layers ,
46
40
} ,
47
- text : {
48
- display : 'flex' ,
49
- justifyContent : 'center' ,
50
- alignItems : 'center' ,
51
- textAlign : 'center' ,
52
- fontSize : '5rem' ,
41
+ parallaxHover__lighting : {
42
+ ...baseStyles . layers ,
53
43
} ,
54
44
} ) ;
55
45
@@ -60,7 +50,7 @@ const initialState = {
60
50
shadowSize : 0 ,
61
51
scale : 1 ,
62
52
shine : 0 ,
63
- isScaling : false ,
53
+ isHovered : false ,
64
54
} ;
65
55
66
56
export default class ParallaxHover extends Component {
@@ -69,17 +59,21 @@ export default class ParallaxHover extends Component {
69
59
this . state = initialState ;
70
60
}
71
61
72
- buildTransformStrings ( depth = 1 ) {
73
- const { scale, rotateX, rotateY } = this . state ;
62
+ componentWillMount ( ) {
63
+ const { shine } = this . props ;
64
+ this . setState ( { shine } ) ;
65
+ }
66
+
67
+ buildTransformStrings ( depth = 0 ) {
68
+ const { rotateX, rotateY } = this . state ;
74
69
75
- const scaleModifier = 1 + ( scale / 100 ) ;
76
70
const rotationXModifier = rotateX + depth ;
77
71
const rotationYModifier = rotateY + depth ;
78
72
79
73
return {
80
- WebkitTransform : `perspective(1000px) scale( ${ scaleModifier } ) rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)` ,
81
- MozTransform : `perspective(1000px) scale( ${ scaleModifier } ) rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)` ,
82
- transform : `perspective(1000px) scale( ${ scaleModifier } ) rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)`
74
+ WebkitTransform : `rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)` ,
75
+ MozTransform : `rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)` ,
76
+ transform : `rotateX(${ rotationXModifier } deg) rotateY(${ rotationYModifier } deg)`
83
77
} ;
84
78
}
85
79
@@ -95,19 +89,28 @@ export default class ParallaxHover extends Component {
95
89
return current / max * shine ;
96
90
}
97
91
92
+ handleParallaxBegin = ( ) => {
93
+ this . setState ( {
94
+ isHovered : true ,
95
+ shine : this . props . shine ,
96
+ } ) ;
97
+ }
98
+
98
99
handleParallaxEnd = ( ) => {
99
100
this . setState ( initialState ) ;
100
101
}
101
102
102
103
handleParallaxMove = ( { pageX, pageY } ) => {
103
104
const { width, height, rotation, scale } = this . props ;
104
- const { scrollTop, scrollLeft } = document . body ;
105
+ const { scrollY : scrollTop , scrollX : scrollLeft } = window ;
106
+
107
+ if ( ! this . state . isHovered ) this . setState ( { isHovered : true } ) ;
105
108
106
109
const bounds = this . wrapper . getBoundingClientRect ( ) ;
107
110
const centerX = width / 2 ;
108
111
const centerY = height / 2 ;
109
112
110
- const widthMultiplier = 320 / width ;
113
+ const widthMultiplier = 360 / width ;
111
114
const offsetX = ( pageX - bounds . left - scrollLeft ) / width ;
112
115
const offsetY = ( pageY - bounds . top - scrollTop ) / height ;
113
116
const deltaX = ( pageX - bounds . left - scrollLeft ) - centerX ;
@@ -119,11 +122,8 @@ export default class ParallaxHover extends Component {
119
122
const angleRad = Math . atan2 ( deltaY , deltaX ) ;
120
123
const angleRaw = angleRad * 180 / Math . PI - 90 ;
121
124
const angle = angleRaw < 0 ? angleRaw + 360 : angleRaw ;
122
- const distanceFromCenter = this . calculateDistance ( bounds , offsetX , offsetY ) ;
123
125
const shadowMovement = centerY * 0.25 ;
124
- const shadowSize = 120 ;
125
-
126
- const shine = this . calculateShineFromCenter ( distanceFromCenter ) ;
126
+ const shadowSize = 110 ;
127
127
128
128
this . setState ( {
129
129
angle,
@@ -132,94 +132,104 @@ export default class ParallaxHover extends Component {
132
132
scale,
133
133
shadowMovement,
134
134
shadowSize,
135
- shine,
136
135
} ) ;
137
136
}
138
137
139
138
renderLayers ( ) {
140
139
const { borderRadius, children } = this . props ;
140
+ const _styles = {
141
+ borderRadius : `${ borderRadius } px` ,
142
+ ...this . buildTransformStrings ( ) ,
143
+ } ;
141
144
142
145
if ( ! Array . isArray ( children ) ) {
143
- const _styles = {
144
- ...this . buildTransformStrings ( ) ,
145
- borderRadius : `${ borderRadius } px`
146
- } ;
147
-
148
146
return (
149
- < div style = { _styles } className = { css ( styles . layer ) } > { children } </ div >
147
+ < div
148
+ style = { _styles }
149
+ className = { css ( styles . parallaxHover__layer ) }
150
+ >
151
+ { children }
152
+ </ div >
150
153
) ;
151
154
}
152
155
153
-
154
156
return children . map ( ( layer , key ) => {
155
- const depth = key + 0.1 ;
156
- const _styles = {
157
- ...this . buildTransformStrings ( depth ) ,
158
- borderRadius : `${ borderRadius } px`
159
- } ;
160
- return < div style = { _styles } className = { css ( styles . layer ) } key = { key } > { layer } </ div > ;
157
+ return (
158
+ < div
159
+ style = { _styles }
160
+ className = { css ( styles . parallaxHover__layer ) }
161
+ key = { key }
162
+ >
163
+ { layer }
164
+ </ div >
165
+ ) ;
161
166
} ) ;
162
167
}
163
168
164
169
render ( ) {
165
- const { angle, shine , shadowMovement, shadowSize } = this . state ;
170
+ const { angle, isHovered , scale , shadowMovement, shadowSize, shine } = this . state ;
166
171
const { borderRadius, width, height } = this . props ;
167
172
168
- // Styles that need to be recalculated on render
169
- // Or passed in from props
173
+ const scaleModifier = isHovered ? ( 1 + scale / 50 ) : 1 ;
174
+
175
+ // Styles that need to be recalculated on render or passed in from props
170
176
const _styles = {
171
- lighting : {
172
- backgroundImage : `linear-gradient(${ angle } deg, rgba(255,255,255, ${ ( shine / 10 ) } ) 0%, rgba(255,255,255,0) 40%)` ,
177
+ overlay : {
178
+ width : `${ width } px` ,
179
+ height : `${ height } px` ,
180
+ transform : `scale(${ scaleModifier } ) perspective(1000px)`
181
+ } ,
182
+ wrapper : {
183
+ height : `${ height } px` ,
184
+ width : `${ width } px` ,
173
185
borderRadius : `${ borderRadius } px` ,
174
- opacity : '1' ,
175
186
...this . buildTransformStrings ( ) ,
176
187
} ,
177
-
178
- shadow : {
179
- boxShadow : `0px ${ shadowMovement } px ${ shadowSize } px rgba(0, 0, 0, 0.6)` ,
188
+ lighting : {
189
+ backgroundImage : `linear-gradient(${ angle } deg, rgba(255,255,255, ${ shine / 10 } ) 0%, rgba(255,255,255,0) 50%)` ,
180
190
borderRadius : `${ borderRadius } px` ,
181
191
...this . buildTransformStrings ( ) ,
182
192
} ,
183
-
184
- wrapper : {
185
- height : `${ height } px` ,
186
- width : `${ width } px` ,
193
+ shadow : {
187
194
borderRadius : `${ borderRadius } px` ,
195
+ boxShadow : `0px ${ shadowMovement } px ${ shadowSize } px rgba(0, 0, 0, 0.5)` ,
188
196
...this . buildTransformStrings ( ) ,
189
197
} ,
190
198
} ;
191
199
192
200
return (
193
- < div className = { css ( styles . outter ) } >
201
+ < div
202
+ className = { css ( styles . parallaxHover__outter ) }
203
+ onMouseEnter = { this . handleParallaxBegin }
204
+ onMouseLeave = { this . handleParallaxEnd }
205
+ onMouseMove = { this . handleParallaxMove }
206
+ onTouchStart = { this . handleParallaxBegin }
207
+ onTouchMove = { this . handleParallaxEnd }
208
+ onTouchEnd = { this . handleParallaxMove }
209
+ style = { _styles . overlay }
210
+ >
211
+ < div className = { css ( styles . parallaxHover__shadow ) } style = { _styles . shadow } />
194
212
< div
195
- className = { css ( styles . wrapper ) }
213
+ className = { css ( styles . parallaxHover__wrapper ) }
196
214
style = { _styles . wrapper }
197
- onMouseEnter = { this . handleParallaxBegin }
198
- onMouseLeave = { this . handleParallaxEnd }
199
- onMouseMove = { this . handleParallaxMove }
200
- onTouchStart = { this . handleParallaxBegin }
201
- onTouchMove = { this . handleParallaxMove }
202
- onTouchEnd = { this . handleParallaxEnd }
203
215
ref = { ( wrapper ) => { this . wrapper = wrapper ; } }
204
216
>
205
- < div className = { css ( styles . shadow ) } style = { _styles . shadow } />
206
- < div className = { css ( styles . layers ) } >
207
- { this . renderLayers ( ) }
208
- </ div >
209
- < div className = { css ( styles . lighting ) } style = { _styles . lighting } />
217
+ { this . renderLayers ( ) }
218
+ < div className = { css ( styles . parallaxHover__lighting ) } style = { _styles . lighting } />
210
219
</ div >
211
220
</ div >
212
221
) ;
213
222
}
214
223
}
215
224
216
225
ParallaxHover . defaultProps = {
217
- speed : 100 , // How fast the item scales up and down in MS
218
- scale : 5 , // How large to scale the item
219
- rotation : 6 , // Rotation modifier
220
- shine : 5 , // Light shine brightness modifer
221
- height : 200 , // Default height
222
- width : 200 , // Default width
226
+ speed : 100 , // How fast the item scales up and down in MS
227
+ scale : 6 , // How large to scale the item
228
+ rotation : 8 , // Rotation modifier
229
+ shine : 5 , // Light shine brightness modifer
230
+ height : 200 , // Default height
231
+ width : 200 , // Default width
232
+ borderRadius : 0 // Default border radius
223
233
} ;
224
234
225
235
ParallaxHover . propTypes = {
0 commit comments