294 lines
7.6 KiB
JavaScript
294 lines
7.6 KiB
JavaScript
/*
|
|
* Horparallax
|
|
*
|
|
* @version 1.0
|
|
*
|
|
* Copyright 2017 UpSolution
|
|
*/
|
|
|
|
! function( $ ) {
|
|
|
|
/*
|
|
********* Horparallax class definition ***********/
|
|
var Horparallax = function( container, options ) {
|
|
// Context
|
|
var that = this;
|
|
this.$window = $( window );
|
|
this.container = $( container );
|
|
// Apply options
|
|
if ( container.onclick != undefined ) {
|
|
options = $.extend( {}, container.onclick() || {}, typeof options == 'object' && options );
|
|
this.container.removeProp( 'onclick' );
|
|
}
|
|
options = $.extend( {}, $.fn.horparallax.defaults, typeof options == 'object' && options );
|
|
this.options = options;
|
|
this.bg = this.container.find( options.bgSelector );
|
|
// Count sizes
|
|
this.containerWidth = this.container.outerWidth();
|
|
this.containerHeight = this.container.outerHeight();
|
|
this.bgWidth = this.bg.outerWidth();
|
|
this.windowHeight = this.$window.height();
|
|
// Count frame rate
|
|
this._frameRate = Math.round( 1000 / this.options.fps );
|
|
// To fix IE bug that handles mousemove before mouseenter
|
|
this.mouseInside = false;
|
|
// Mouse events for desktop browsers
|
|
if ( ! ( 'ontouchstart' in window ) || ! ( 'DeviceOrientationEvent' in window ) ) {
|
|
this.container
|
|
.mouseenter( function( e ) {
|
|
// To fix IE bug that handles mousemove before mouseenter
|
|
that.mouseInside = true;
|
|
var offset = that.container.offset(),
|
|
coord = ( e.pageX - offset.left ) / that.containerWidth;
|
|
that.cancel();
|
|
that._hoverAnimation = true;
|
|
that._hoverFrom = that.now;
|
|
that._hoverTo = coord;
|
|
that.start( that._hoverTo );
|
|
} )
|
|
.mousemove( function( e ) {
|
|
// To fix IE bug that handles mousemove before mouseenter
|
|
if ( ! that.mouseInside ) {
|
|
return;
|
|
}
|
|
// Reducing processor load for too frequent event calls
|
|
if ( that._lastFrame + that._frameRate > Date.now() ) {
|
|
return;
|
|
}
|
|
var offset = that.container.offset(),
|
|
coord = ( e.pageX - offset.left ) / that.containerWidth;
|
|
// Handle hover animation
|
|
if ( that._hoverAnimation ) {
|
|
that._hoverTo = coord;
|
|
return;
|
|
}
|
|
that.set( coord );
|
|
that._lastFrame = Date.now();
|
|
} )
|
|
.mouseleave( function( e ) {
|
|
that.mouseInside = false;
|
|
that.cancel();
|
|
that.start( that.options.basePoint );
|
|
} );
|
|
}
|
|
// Handle resize
|
|
this.$window.resize( function() {
|
|
that.handleResize();
|
|
} );
|
|
// Device orientation events for touch devices
|
|
this._orientationDriven = ( 'ontouchstart' in window && 'DeviceOrientationEvent' in window );
|
|
if ( this._orientationDriven ) {
|
|
// Check if container is visible
|
|
this._checkIfVisible();
|
|
window.addEventListener( "deviceorientation", function( e ) {
|
|
// Reducing processor load for too frequent event calls
|
|
if ( ! that.visible || that._lastFrame + that._frameRate > Date.now() ) {
|
|
return;
|
|
}
|
|
that._deviceOrientationChange( e );
|
|
that._lastFrame = Date.now();
|
|
} );
|
|
this.$window.resize( function() {
|
|
that._checkIfVisible();
|
|
} );
|
|
this.$window.scroll( function() {
|
|
that._checkIfVisible();
|
|
} );
|
|
}
|
|
// Set to basepoint
|
|
this.set( this.options.basePoint );
|
|
this._lastFrame = Date.now();
|
|
};
|
|
|
|
Horparallax.prototype = {
|
|
|
|
/**
|
|
* Event to fire on deviceorientation change
|
|
* @private
|
|
*/
|
|
_deviceOrientationChange: function( e ) {
|
|
var gamma = e.gamma,
|
|
beta = e.beta,
|
|
x, y;
|
|
switch ( window.orientation ) {
|
|
case - 90:
|
|
beta = Math.max( - 45, Math.min( 45, beta ) );
|
|
x = ( beta + 45 ) / 90;
|
|
break;
|
|
case 90:
|
|
beta = Math.max( - 45, Math.min( 45, beta ) );
|
|
x = ( 45 - beta ) / 90;
|
|
break;
|
|
case 180:
|
|
gamma = Math.max( - 45, Math.min( 45, gamma ) );
|
|
x = ( gamma + 45 ) / 90;
|
|
break;
|
|
case 0:
|
|
default:
|
|
// Upside down
|
|
if ( gamma < - 90 || gamma > 90 ) {
|
|
gamma = Math.abs( e.gamma ) / e.gamma * ( 180 - Math.abs( e.gamma ) );
|
|
}
|
|
gamma = Math.max( - 45, Math.min( 45, gamma ) );
|
|
x = ( 45 - gamma ) / 90;
|
|
break;
|
|
}
|
|
this.set( x );
|
|
},
|
|
|
|
/**
|
|
* Handle container resize
|
|
*/
|
|
handleResize: function() {
|
|
this.containerWidth = this.container.outerWidth();
|
|
this.containerHeight = this.container.outerHeight();
|
|
this.bgWidth = this.bg.outerWidth();
|
|
this.windowHeight = this.$window.height();
|
|
this.set( this.now );
|
|
},
|
|
|
|
/**
|
|
* Update container visibility status (to prevent unnessesary rendering)
|
|
* @private
|
|
*/
|
|
_checkIfVisible: function() {
|
|
var scrollTop = this.$window.scrollTop(),
|
|
containerTop = this.container.offset().top;
|
|
this.visible = ( containerTop + this.containerHeight > scrollTop && containerTop < scrollTop + this.windowHeight );
|
|
},
|
|
|
|
/**
|
|
* Render horparallax frame.
|
|
* @param {Array} x is ranged in [0, 1]
|
|
*/
|
|
set: function( x ) {
|
|
this.bg.css( 'left', ( this.containerWidth - this.bgWidth ) * x );
|
|
this.now = x;
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Step value computing function, read more at http://mootools.net/docs/core/Fx/Fx
|
|
* @param {Number} from
|
|
* @param {Number} to
|
|
* @param {Number} delta
|
|
* @return {Number}
|
|
*/
|
|
compute: function( from, to, delta ) {
|
|
if ( this._hoverAnimation ) {
|
|
return ( this._hoverTo - this._hoverFrom ) * delta + this._hoverFrom;
|
|
}
|
|
return ( to - from ) * delta + from;
|
|
},
|
|
|
|
/**
|
|
* Start animation to certain point
|
|
* @param {Array} to
|
|
* @return {Horparallax}
|
|
*/
|
|
start: function( to ) {
|
|
var from = this.now,
|
|
that = this;
|
|
this.container
|
|
.css( 'delta', 0 )
|
|
.animate( {
|
|
delta: 1
|
|
}, {
|
|
duration: this.options.duration,
|
|
easing: this.options.easing,
|
|
complete: function() {
|
|
that._hoverAnimation = false;
|
|
},
|
|
step: function( delta ) {
|
|
that.set( that.compute( from, to, delta ) );
|
|
},
|
|
queue: false
|
|
} );
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Cancel animation
|
|
* @return {Horparallax}
|
|
*/
|
|
cancel: function() {
|
|
this._hoverAnimation = false;
|
|
this.container.stop( true, false );
|
|
return this;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
// EaseOutElastic easing
|
|
if ( $.easing.easeOutElastic == undefined ) {
|
|
/**
|
|
* Original function by George McGinley Smith
|
|
* @link http://gsgd.co.uk/sandbox/jquery/easing/
|
|
*/
|
|
$.easing.easeOutElastic = function( x, t, b, c, d ) {
|
|
var s = 1.70158, p = 0, a = c;
|
|
if ( t == 0 ) {
|
|
return b;
|
|
}
|
|
if ( ( t /= d ) == 1 ) {
|
|
return b + c;
|
|
}
|
|
if ( ! p ) {
|
|
p = d * .3;
|
|
}
|
|
if ( a < Math.abs( c ) ) {
|
|
a = c;
|
|
var s = p / 4;
|
|
}
|
|
else {
|
|
var s = p / ( 2 * Math.PI ) * Math.asin( c / a );
|
|
}
|
|
return a * Math.pow( 2, - 10 * t ) * Math.sin( ( t * d - s ) * ( 2 * Math.PI ) / p ) + c + b;
|
|
};
|
|
}
|
|
|
|
$.fn.horparallax = function( options ) {
|
|
return this.each( function() {
|
|
var $this = $( this ),
|
|
data = $this.data( 'horparallax' );
|
|
if ( ! data ) {
|
|
$this.data( 'horparallax', ( data = new Horparallax( this, options ) ) )
|
|
}
|
|
} );
|
|
};
|
|
|
|
$.fn.horparallax.defaults = {
|
|
/**
|
|
* @var {Number} Frame per second limit for rendering
|
|
*/
|
|
fps: 60,
|
|
|
|
/**
|
|
* @var {Number} Point for basic position (after the cursor moves out of the container)
|
|
*/
|
|
basePoint: .5,
|
|
|
|
/**
|
|
* @var {Number} Return to base point duration
|
|
*/
|
|
duration: 500,
|
|
|
|
/**
|
|
* @var {String} Background layer selector
|
|
*/
|
|
bgSelector: '.l-section-img',
|
|
|
|
/**
|
|
* @var {Function} Returning-to-basepoint easing
|
|
*/
|
|
easing: 'swing'// 'easeOutElastic'
|
|
};
|
|
|
|
$.fn.horparallax.Constructor = Horparallax;
|
|
|
|
$( function() {
|
|
jQuery( '.parallax_hor' ).horparallax();
|
|
} );
|
|
|
|
}( jQuery ); |