1+ ( function ( factory ) {
2+ if ( typeof define === 'function' && define . amd ) {
3+ // AMD. Register as an anonymous module.
4+ define ( [ 'jquery' ] , factory ) ;
5+ } else if ( typeof module === 'object' && module . exports ) {
6+ // Node/CommonJS
7+ module . exports = function ( root , jQuery ) {
8+ if ( jQuery === undefined ) {
9+ // require('jQuery') returns a factory that requires window to
10+ // build a jQuery instance, we normalize how we use modules
11+ // that require this pattern but the window provided is a noop
12+ // if it's defined (how jquery works)
13+ if ( typeof window !== 'undefined' ) {
14+ jQuery = require ( 'jquery' ) ;
15+ }
16+ else {
17+ jQuery = require ( 'jquery' ) ( root ) ;
18+ }
19+ }
20+ factory ( jQuery ) ;
21+ return jQuery ;
22+ } ;
23+ } else {
24+ // Browser globals
25+ factory ( jQuery ) ;
26+ }
27+ } ( function ( $ ) {
28+ $ . fn . tilt = function ( options ) {
29+
30+ /**
31+ * RequestAnimationFrame
32+ */
33+ const requestTick = function ( ) {
34+ if ( this . ticking ) return ;
35+ requestAnimationFrame ( updateTransforms . bind ( this ) ) ;
36+ this . ticking = true ;
37+ } ;
38+
39+ /**
40+ * Bind mouse movement evens on instance
41+ */
42+ const bindEvents = function ( ) {
43+ const _this = this ;
44+ $ ( this ) . on ( 'mousemove' , mouseMove ) ;
45+ $ ( this ) . on ( 'mouseenter' , mouseEnter ) ;
46+ if ( this . settings . reset ) $ ( this ) . on ( 'mouseleave' , mouseLeave ) ;
47+ if ( this . settings . glare ) $ ( window ) . on ( 'resize' , updateGlareSize . bind ( _this ) ) ;
48+ } ;
49+
50+ /**
51+ * Set transition only on mouse leave and mouse enter so it doesn't influence mouse move transforms
52+ */
53+ const setTransition = function ( ) {
54+ if ( this . timeout !== undefined ) clearTimeout ( this . timeout ) ;
55+ $ ( this ) . css ( { 'transition' : `${ this . settings . speed } ms ${ this . settings . easing } ` } ) ;
56+ if ( this . settings . glare ) this . glareElement . css ( { 'transition' : `opacity ${ this . settings . speed } ms ${ this . settings . easing } ` } ) ;
57+ this . timeout = setTimeout ( ( ) => {
58+ $ ( this ) . css ( { 'transition' : '' } ) ;
59+ if ( this . settings . glare ) this . glareElement . css ( { 'transition' : '' } ) ;
60+ } , this . settings . speed ) ;
61+ } ;
62+
63+ /**
64+ * When user mouse enters tilt element
65+ */
66+ const mouseEnter = function ( event ) {
67+ this . ticking = false ;
68+ $ ( this ) . css ( { 'will-change' : 'transform' } ) ;
69+ setTransition . call ( this ) ;
70+
71+ // Trigger change event
72+ $ ( this ) . trigger ( "tilt.mouseEnter" ) ;
73+ } ;
74+
75+ /**
76+ * Return the x,y position of the mouse on the tilt element
77+ * @returns {{x: *, y: *} }
78+ */
79+ const getMousePositions = function ( event ) {
80+ if ( typeof ( event ) === "undefined" ) {
81+ event = {
82+ pageX : $ ( this ) . offset ( ) . left + $ ( this ) . outerWidth ( ) / 2 ,
83+ pageY : $ ( this ) . offset ( ) . top + $ ( this ) . outerHeight ( ) / 2
84+ } ;
85+ }
86+ return { x : event . pageX , y : event . pageY } ;
87+ } ;
88+
89+ /**
90+ * When user mouse moves over the tilt element
91+ */
92+ const mouseMove = function ( event ) {
93+ this . mousePositions = getMousePositions ( event ) ;
94+ requestTick . call ( this ) ;
95+ } ;
96+
97+ /**
98+ * When user mouse leaves tilt element
99+ */
100+ const mouseLeave = function ( ) {
101+ setTransition . call ( this ) ;
102+ this . reset = true ;
103+ requestTick . call ( this ) ;
104+
105+ // Trigger change event
106+ $ ( this ) . trigger ( "tilt.mouseLeave" ) ;
107+ } ;
108+
109+ /**
110+ * Get tilt values
111+ *
112+ * @returns {{x: tilt value, y: tilt value} }
113+ */
114+ const getValues = function ( ) {
115+ const width = $ ( this ) . outerWidth ( ) ;
116+ const height = $ ( this ) . outerHeight ( ) ;
117+ const left = $ ( this ) . offset ( ) . left ;
118+ const top = $ ( this ) . offset ( ) . top ;
119+ const percentageX = ( this . mousePositions . x - left ) / width ;
120+ const percentageY = ( this . mousePositions . y - top ) / height ;
121+ // x or y position inside instance / width of instance = percentage of position inside instance * the max tilt value
122+ const tiltX = ( ( this . settings . maxTilt / 2 ) - ( ( percentageX ) * this . settings . maxTilt ) ) . toFixed ( 2 ) ;
123+ const tiltY = ( ( ( percentageY ) * this . settings . maxTilt ) - ( this . settings . maxTilt / 2 ) ) . toFixed ( 2 ) ;
124+ // angle
125+ const angle = Math . atan2 ( this . mousePositions . x - ( left + width / 2 ) , - ( this . mousePositions . y - ( top + height / 2 ) ) ) * ( 180 / Math . PI ) ;
126+ // Return x & y tilt values
127+ return { tiltX, tiltY, 'percentageX' : percentageX * 100 , 'percentageY' : percentageY * 100 , angle} ;
128+ } ;
129+
130+ /**
131+ * Update tilt transforms on mousemove
132+ */
133+ const updateTransforms = function ( ) {
134+ this . transforms = getValues . call ( this ) ;
135+
136+ if ( this . reset ) {
137+ this . reset = false ;
138+ $ ( this ) . css ( 'transform' , `perspective(${ this . settings . perspective } px) rotateX(0deg) rotateY(0deg)` ) ;
139+
140+ // Rotate glare if enabled
141+ if ( this . settings . glare ) {
142+ this . glareElement . css ( 'transform' , `rotate(180deg) translate(-50%, -50%)` ) ;
143+ this . glareElement . css ( 'opacity' , `0` ) ;
144+ }
145+
146+ return ;
147+ } else {
148+ $ ( this ) . css ( 'transform' , `perspective(${ this . settings . perspective } px) rotateX(${ this . settings . disableAxis === 'x' ? 0 : this . transforms . tiltY } deg) rotateY(${ this . settings . disableAxis === 'y' ? 0 : this . transforms . tiltX } deg) scale3d(${ this . settings . scale } ,${ this . settings . scale } ,${ this . settings . scale } )` ) ;
149+
150+ // Rotate glare if enabled
151+ if ( this . settings . glare ) {
152+ this . glareElement . css ( 'transform' , `rotate(${ this . transforms . angle } deg) translate(-50%, -50%)` ) ;
153+ this . glareElement . css ( 'opacity' , `${ this . transforms . percentageY * this . settings . maxGlare / 100 } ` ) ;
154+ }
155+ }
156+
157+ // Trigger change event
158+ $ ( this ) . trigger ( "change" , [ this . transforms ] ) ;
159+
160+ this . ticking = false ;
161+ } ;
162+
163+ /**
164+ * Prepare elements
165+ */
166+ const prepareGlare = function ( ) {
167+ const glarePrerender = this . settings . glarePrerender ;
168+
169+ // If option pre-render is enabled we assume all html/css is present for an optimal glare effect.
170+ if ( ! glarePrerender )
171+ // Create glare element
172+ $ ( this ) . append ( '<div class="js-tilt-glare"><div class="js-tilt-glare-inner"></div></div>' ) ;
173+
174+ // Store glare selector if glare is enabled
175+ this . glareElementWrapper = $ ( this ) . find ( ".js-tilt-glare" ) ;
176+ this . glareElement = $ ( this ) . find ( ".js-tilt-glare-inner" ) ;
177+
178+ // Remember? We assume all css is already set, so just return
179+ if ( glarePrerender ) return ;
180+
181+ // Abstracted re-usable glare styles
182+ const stretch = {
183+ 'position' : 'absolute' ,
184+ 'top' : '0' ,
185+ 'left' : '0' ,
186+ 'width' : '100%' ,
187+ 'height' : '100%' ,
188+ } ;
189+
190+ // Style glare wrapper
191+ this . glareElementWrapper . css ( stretch ) . css ( {
192+ 'overflow' : 'hidden' ,
193+ 'pointer-events' : 'none' ,
194+ } ) ;
195+
196+ // Style glare element
197+ this . glareElement . css ( {
198+ 'position' : 'absolute' ,
199+ 'top' : '50%' ,
200+ 'left' : '50%' ,
201+ 'background-image' : `linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%)` ,
202+ 'width' : `${ $ ( this ) . outerWidth ( ) * 2 } ` ,
203+ 'height' : `${ $ ( this ) . outerWidth ( ) * 2 } ` ,
204+ 'transform' : 'rotate(180deg) translate(-50%, -50%)' ,
205+ 'transform-origin' : '0% 0%' ,
206+ 'opacity' : '0' ,
207+ } ) ;
208+
209+ } ;
210+
211+ /**
212+ * Update glare on resize
213+ */
214+ const updateGlareSize = function ( ) {
215+ this . glareElement . css ( {
216+ 'width' : `${ $ ( this ) . outerWidth ( ) * 2 } ` ,
217+ 'height' : `${ $ ( this ) . outerWidth ( ) * 2 } ` ,
218+ } ) ;
219+ } ;
220+
221+ /**
222+ * Public methods
223+ */
224+ $ . fn . tilt . destroy = function ( ) {
225+ $ ( this ) . each ( function ( ) {
226+ $ ( this ) . find ( '.js-tilt-glare' ) . remove ( ) ;
227+ $ ( this ) . css ( { 'will-change' : '' , 'transform' : '' } ) ;
228+ $ ( this ) . off ( 'mousemove mouseenter mouseleave' ) ;
229+ } ) ;
230+ } ;
231+
232+ $ . fn . tilt . getValues = function ( ) {
233+ const results = [ ] ;
234+ $ ( this ) . each ( function ( ) {
235+ this . mousePositions = getMousePositions . call ( this ) ;
236+ results . push ( getValues . call ( this ) ) ;
237+ } ) ;
238+ return results ;
239+ } ;
240+
241+ $ . fn . tilt . reset = function ( ) {
242+ $ ( this ) . each ( function ( ) {
243+ this . mousePositions = getMousePositions . call ( this ) ;
244+ this . settings = $ ( this ) . data ( 'settings' ) ;
245+ mouseLeave . call ( this ) ;
246+ setTimeout ( ( ) => {
247+ this . reset = false ;
248+ } , this . settings . transition ) ;
249+ } ) ;
250+ } ;
251+
252+ /**
253+ * Loop every instance
254+ */
255+ return this . each ( function ( ) {
256+
257+ /**
258+ * Default settings merged with user settings
259+ * Can be set trough data attributes or as parameter.
260+ * @type {* }
261+ */
262+ this . settings = $ . extend ( {
263+ maxTilt : $ ( this ) . is ( '[data-tilt-max]' ) ? $ ( this ) . data ( 'tilt-max' ) : 20 ,
264+ perspective : $ ( this ) . is ( '[data-tilt-perspective]' ) ? $ ( this ) . data ( 'tilt-perspective' ) : 300 ,
265+ easing : $ ( this ) . is ( '[data-tilt-easing]' ) ? $ ( this ) . data ( 'tilt-easing' ) : 'cubic-bezier(.03,.98,.52,.99)' ,
266+ scale : $ ( this ) . is ( '[data-tilt-scale]' ) ? $ ( this ) . data ( 'tilt-scale' ) : '1' ,
267+ speed : $ ( this ) . is ( '[data-tilt-speed]' ) ? $ ( this ) . data ( 'tilt-speed' ) : '400' ,
268+ transition : $ ( this ) . is ( '[data-tilt-transition]' ) ? $ ( this ) . data ( 'tilt-transition' ) : true ,
269+ disableAxis : $ ( this ) . is ( '[data-tilt-disable-axis]' ) ? $ ( this ) . data ( 'tilt-disable-axis' ) : null ,
270+ axis : $ ( this ) . is ( '[data-tilt-axis]' ) ? $ ( this ) . data ( 'tilt-axis' ) : null ,
271+ reset : $ ( this ) . is ( '[data-tilt-reset]' ) ? $ ( this ) . data ( 'tilt-reset' ) : true ,
272+ glare : $ ( this ) . is ( '[data-tilt-glare]' ) ? $ ( this ) . data ( 'tilt-glare' ) : false ,
273+ maxGlare : $ ( this ) . is ( '[data-tilt-maxglare]' ) ? $ ( this ) . data ( 'tilt-maxglare' ) : 1 ,
274+ } , options ) ;
275+
276+ // Add deprecation warning & set disableAxis to deprecated axis setting
277+ if ( this . settings . axis !== null ) {
278+ console . warn ( 'Tilt.js: the axis setting has been renamed to disableAxis. See https://github.com/gijsroge/tilt.js/pull/26 for more information' ) ;
279+ this . settings . disableAxis = this . settings . axis ;
280+ }
281+
282+ this . init = ( ) => {
283+ // Store settings
284+ $ ( this ) . data ( 'settings' , this . settings ) ;
285+
286+ // Prepare element
287+ if ( this . settings . glare ) prepareGlare . call ( this ) ;
288+
289+ // Bind events
290+ bindEvents . call ( this ) ;
291+ } ;
292+
293+ // Init
294+ this . init ( ) ;
295+
296+ } ) ;
297+ } ;
298+
299+ /**
300+ * Auto load
301+ */
302+ $ ( '[data-tilt]' ) . tilt ( ) ;
303+
304+ return true ;
305+ } ) ) ;
0 commit comments