From bf3980cf532f0d6b9a7b3dda60e78ea2ddd54731 Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Tue, 10 Apr 2012 09:10:26 +0200 Subject: [PATCH 1/9] Updated to jquery 1.7.x --- index.html | 2 +- js/jquery.jparallax.js | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index b47880a..1a0bffa 100644 --- a/index.html +++ b/index.html @@ -351,7 +351,7 @@

Bug reporting

- + diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index b0c69ad..cc41e62 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -9,10 +9,10 @@ // github.com/stephband/jparallax // // Dependencies: -// jquery.event.frame +// $.event.frame // webdev.stephband.info/events/frame/ -(function(jQuery, undefined) { +(function($) { // Plugin name var plugin = "parallax"; @@ -99,9 +99,47 @@ function Mouse(options, pointer){ }; } +function DeviceMotion(options, pointer){ + + // Convert parallax options to boolean values + var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; + + this.ontarget = false; + this.decay = options.decay; + this.pointer = pointer || [0.5, 0.5]; + this.update = function(pointer, threshold){ + + // Pointer is already on target + if (this.ontarget) { + this.pointer = pointer; + } + + // Pointer has arrived within the target thresholds + else if ( (!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && + (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1]) ) { + + this.ontarget = true; + this.pointer = pointer; + } + + // Pointer is nowhere near the target + else { + var lagPointer = [], + x = 2; + + while (x--) { + if ( parallax[x] ) { + lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]) ; + } + } + this.pointer = lagPointer; + } + }; +} + function Port(object, options){ var self = this, - elem = object instanceof jQuery ? object : jQuery(object) , + elem = object instanceof $ ? object : $(object) , // Convert parallax options to boolean values parallax = [parseBool(options.xparallax), parseBool(options.yparallax)], // State of mouse position (0 - outside, 1 - inside, 2 - just gone outside) @@ -161,7 +199,7 @@ function Port(object, options){ }; // Update mouseport dimensions on window resize - jQuery(window) + $(window) .on('resize.'+plugin, self.updateSize) .on('resize.'+plugin, self.updatePos); @@ -297,188 +335,194 @@ function Layer(elem, options){ // EVENT HANDLERS function update(e){ - - var elem = jQuery(this), - global = e.data, - local = elem.data(plugin), - port = global.port, - mouse = global.mouse, - localmouse = local.mouse, - process = global.timeStamp !== e.timeStamp; - - // Global objects have yet to be processed for this frame - if ( process ) { - // Set timeStamp to current time - global.timeStamp = e.timeStamp; - - // Process mouseport - port.update(pointer); - - // Process mouse - if ( port.active || !mouse.ontarget ) { - mouse.update(port.pointer, port.threshold); + if (window.DeviceMotionEvent) { + var elem = $(this), + local = elem.data(plugin); + + console.log(e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y); + //local.layer.update([e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y]); + } else { + var elem = $(this), + global = e.data, + local = elem.data(plugin), + port = global.port, + mouse = global.mouse, + localmouse = local.mouse, + process = global.timeStamp !== e.timeStamp; + + // Global objects have yet to be processed for this frame + if ( process ) { + // Set timeStamp to current time + global.timeStamp = e.timeStamp; + + // Process mouseport + port.update(pointer); + + // Process mouse + if ( port.active || !mouse.ontarget ) { + mouse.update(port.pointer, port.threshold); + } } - } - - // Layer has it's own mouse - if ( localmouse ) { - - // Process mouse - localmouse.update( local.freeze ? local.freeze.pointer : port.pointer, port.threshold ); - - // If it hits target - if ( localmouse.ontarget ) { - - delete local.mouse; - - // Stop animating frozen layers - if (local.freeze) { - elem - .off(frameEvent) - .addClass(global.freezeClass); + + // Layer has it's own mouse + if ( localmouse ) { + + // Process mouse + localmouse.update( local.freeze ? local.freeze.pointer : port.pointer, port.threshold ); + + // If it hits target + if ( localmouse.ontarget ) { + + delete local.mouse; + + // Stop animating frozen layers + if (local.freeze) { + elem + .off(frameEvent) + .addClass(global.freezeClass); + } } + + // Use localmouse in place of mouse + mouse = localmouse; } - - // Use localmouse in place of mouse - mouse = localmouse; - } - // Layer is responding to global mouse - else { - // When no longer active, unbind - if ( mouse.ontarget && !port.active ) { - elem.off(frameEvent); + // Layer is responding to global mouse + else { + // When no longer active, unbind + if ( mouse.ontarget && !port.active ) { + elem.off(frameEvent); + } } + + local.layer.update(mouse.pointer); } - - local.layer.update(mouse.pointer); } -jQuery.fn[plugin] = function(o){ - if (undefined === jQuery.event.special.frame) { - throw "jquery.event.frame is required for jparallax to work" +$.fn[plugin] = function(o){ + if (undefined === $.event.special.frame) { + throw "$.event.frame is required for jparallax to work" } - var global = jQuery.extend({}, jQuery.fn[plugin].options, o), + + var global = $.extend({}, $.fn[plugin].options, o), args = arguments, layers = this; - - // Turn mouseport into jQuery obj - if ( !(global.mouseport instanceof jQuery) ) { - global.mouseport = jQuery(global.mouseport); + + if (window.DeviceMotionEvent) { + global.DeviceMotionEvent = true; + } else { + global.DeviceMotionEvent = false; } - - global.port = new Port(global.mouseport, global); - global.mouse = new Mouse(global); - - global.mouseport - .on("mouseenter", function(e){ - global.mouse.ontarget = false; - - // Animate unfrozen layers - layers - .each(function(i){ - var layer = jQuery(this); - - if ( !layer.data(plugin).freeze ) { - layer + + if (global.DeviceMotionEvent === false) { + // Turn mouseport into $ obj + if ( !(global.mouseport instanceof $) ) { + global.mouseport = $(global.mouseport); + } + + global.port = new Port(global.mouseport, global); + global.mouse = new Mouse(global); + + global.mouseport + .on("mouseenter", function(e){ + global.mouse.ontarget = false; + // Animate unfrozen layers + layers + .each(function(i){ + var layer = $(this); + + if ( !layer.data(plugin).freeze ) { + layer + .on(frameEvent, global, update); + } + }); + }); + + return layers + .on("freeze", function(e){ + var elem = $(this), + local = elem.data(plugin), + mouse = local.mouse || local.freeze || global.mouse, + coords = coords = [ + e.x === undefined ? mouse.pointer[0] : parseCoord(e.x), + e.y === undefined ? mouse.pointer[1] : parseCoord(e.y) + ], + decay = e.decay; + + // Store position + local.freeze = { + pointer: coords + }; + + // Create local mouse, passing in current pointer with options + local.mouse = new Mouse(global, mouse.pointer); + + if (decay !== undefined) { + local.mouse.decay = decay; + }; + + // Start animating + elem.on(frameEvent, global, update); + }) + .on("unfreeze", function(e){ + var elem = $(this), + local = elem.data(plugin), + decay = e.decay, + pointer; + + if (local.freeze) { + + // Create local mouse, passing local freeze pointer with options + pointer = local.mouse ? local.mouse.pointer : local.freeze.pointer ; + local.mouse = new Mouse(global); + local.mouse.pointer = pointer; + + // Override decay with decay passed as e.decay + if (decay !== undefined) local.mouse.decay = decay; + + // Destroy local.freeze + delete local.freeze; + + // Remove freeze class and start animating + elem + .removeClass(options.freezeClass) .on(frameEvent, global, update); } + }) + .each(function(i){ + var elem = $(this), + + // Construct layer options from extra arguments + layerOptions = args[i+1] ? $.extend({}, global, args[i+1]) : global , + layer = new Layer(elem, layerOptions); + + // Set up layer data. Give it a local mouse + // initialises it to start smoothly from current position + elem.data(plugin, { + layer: layer, + mouse: new Mouse(layerOptions, layer.getPointer()) + }); }); - }); - - return layers - //.on("move", function(e){ - // var elem = jQuery(this), - // local = elem.data(plugin), - // mouse = local.mouse || local.freeze || global.mouse, - // coords = [ - // e.x === undefined ? mouse.pointer[0] : parseCoord(e.x), - // e.y === undefined ? mouse.pointer[1] : parseCoord(e.y) - // ], - // decay = e.decay; - // - // // Fake the mouse - // global.mouse.ontarget = false; - // global.port.pointer = coords; - // - // // Start animating - // elem.on(frameEvent, global, update); - //}) - .on("freeze", function(e){ - var elem = jQuery(this), - local = elem.data(plugin), - mouse = local.mouse || local.freeze || global.mouse, - coords = coords = [ - e.x === undefined ? mouse.pointer[0] : parseCoord(e.x), - e.y === undefined ? mouse.pointer[1] : parseCoord(e.y) - ], - decay = e.decay; - - // Store position - local.freeze = { - pointer: coords - }; - - // Create local mouse, passing in current pointer with options - local.mouse = new Mouse(global, mouse.pointer); - - if (decay !== undefined) { - local.mouse.decay = decay; - }; - - // Start animating - elem.on(frameEvent, global, update); - }) - .on("unfreeze", function(e){ - var elem = jQuery(this), - local = elem.data(plugin), - decay = e.decay, - pointer; - - if (local.freeze) { - - // Create local mouse, passing local freeze pointer with options - pointer = local.mouse ? local.mouse.pointer : local.freeze.pointer ; - local.mouse = new Mouse(global); - local.mouse.pointer = pointer; - - // Override decay with decay passed as e.decay - if (decay !== undefined) local.mouse.decay = decay; - - // Destroy local.freeze - delete local.freeze; - - // Remove freeze class and start animating - elem - .removeClass(options.freezeClass) - .on(frameEvent, global, update); - } - }) - .each(function(i){ - var elem = jQuery(this), - - // Construct layer options from extra arguments - layerOptions = args[i+1] ? jQuery.extend({}, global, args[i+1]) : global , - layer = new Layer(elem, layerOptions); - - // Set up layer data. Give it a local mouse - // initialises it to start smoothly from current position - elem.data(plugin, { - layer: layer, - mouse: new Mouse(layerOptions, layer.getPointer()) - }); - }); + } else { + var self = this; + + window.addEventListener('devicemotion', function () { + layers.trigger('DeviceMotionEvent', this); + }, false); + + return layers.on('DeviceMotionEvent', global, update); + } }; // EXPOSE -jQuery.fn[plugin].options = options; + jQuery.fn[plugin].options = options; // RUN -jQuery(document).ready(function(){ - // Pick up and store mouse position on jQuery(document) - // IE does not register mousemove on jQuery(window) - jQuery(document) +$(document).ready(function(){ + // Pick up and store mouse position on $(document) + // IE does not register mousemove on $(window) + $(document) .mousemove(function(e){ pointer = [e.pageX, e.pageY]; }); From aaa30c7ad095789196ee7b30e4155a5cf184208a Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Wed, 11 Apr 2012 00:24:04 +0200 Subject: [PATCH 4/9] checks --- js/jquery.jparallax.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index cc41e62..acd3c27 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -339,7 +339,9 @@ function update(e){ var elem = $(this), local = elem.data(plugin); - console.log(e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y); + e.forEach(function (val, key) { + console.log(key, val); + }); //local.layer.update([e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y]); } else { var elem = $(this), @@ -505,8 +507,8 @@ $.fn[plugin] = function(o){ } else { var self = this; - window.addEventListener('devicemotion', function () { - layers.trigger('DeviceMotionEvent', this); + window.addEventListener('devicemotion', function (e) { + layers.trigger('DeviceMotionEvent', e); }, false); return layers.on('DeviceMotionEvent', global, update); From c65c7b51b7476068bcb747482e96008f541599f7 Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Thu, 12 Apr 2012 20:24:32 +0200 Subject: [PATCH 5/9] basic parallax with iDevice --- .gitignore | 3 +- index.html | 839 ++++++++++++++++++++++++----------------- js/jquery.jparallax.js | 30 +- 3 files changed, 525 insertions(+), 347 deletions(-) diff --git a/.gitignore b/.gitignore index 3d72576..6d84185 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -.idea \ No newline at end of file +.idea +node_modules \ No newline at end of file diff --git a/index.html b/index.html index 1de7467..c1c49de 100644 --- a/index.html +++ b/index.html @@ -3,292 +3,436 @@ - + -webdev.stephband.info + webdev.stephband.info - + - + #contact { + margin-right: 0.5em; + } + + #pullnav a:focus, #pullnav a:hover { + color: #222222; + text-decoration: none; + } + + #pullnav a { + color: #505050; + } + + #pullnav form textarea { + width: 240px; + height: 80px; + } + + #pullnav #donate input { + margin: 0 1.2em; + } + + #pullnav #donate { + display: none; + } + + #pullnav #message { + display: none; + } + + #pullnav #message .website { + display: none; + } + + #pullnav .error { + color: #7d4819; + } + + input[type='text'] { + margin-left: 0; + } + + input[type='text'], textarea { + border: 1px solid #333333; + padding: 0.3em; + -webkit-border-radius: 0.6em; + -moz-border-radius: 0.6em; + border-radius: 0.6em; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + + .options { + margin-top: 1em; + } + + .options td { + vertical-align: top; + padding: 0 0.4em; + } + + .options thead td { + background: #e8ecf0; + border-bottom: 1em solid white; + padding: 0.2em 0.4em; + } + + pre { + font-family: Courier, 'Monaco', 'Andale Mono'; + } + + .options .key, + .options .value, + .options .default { + font-family: Courier, 'Monaco', 'Andale Mono'; + padding-right: 1em; + font-weight: bold; + } + + .options .key { + width: 8em; + } + + .options .default { + width: 12em; + } + + .options .note { + padding-bottom: 1em; + } + + #housing { + padding-top: 16px; + } + + small { + text-transform: uppercase; + } + +
- -

jParallax

- -

Download

- -

Note: jParallax 1.0 is not a drop-in replacement for jParallax 0.9.x. If you are already using the beta and want to switch, please read the changelog for an overview.

- -

Instantiation

-
jQuery( '.parallax-layer' ).parallax( options );
- -

What does jParallax do?

- Diagram of parallax layers. -

jParallax turns nodes into absolutely positioned layers that move in response to the mouse. Depending on their dimensions these layers move at different rates, in a parallaxy kind of way.

-

With a bit of CSS you can either set up windows to see these layers through, or leave them free to roam about.

-

The diagram on the right illustrates what jParallax does to the html:

+ +

jParallax

+ +

Download

+ +

Note: jParallax 1.0 is not a drop-in replacement for jParallax 0.9.x. If you are already using the beta and want to + switch, please read the changelog for an overview.

+ +

Instantiation

+
jQuery( '.parallax-layer' ).parallax( options );
+ +

What does jParallax do?

+Diagram of parallax layers. + +

jParallax turns nodes into absolutely positioned layers that move in response to the mouse. Depending on their + dimensions these layers move at different rates, in a parallaxy kind of way.

+ +

With a bit of CSS you can either set up windows to see these layers through, or leave them free to roam about.

+ +

The diagram on the right illustrates what jParallax does to the html:

-
<ul>
-  <li class="parallax-layer"></li>
-  <li class="parallax-layer"></li>
+
<ul>
+  <li class="parallax-layer"></li>
+  <li class="parallax-layer"></li>
 </ul>
- -

and here's a demonstration with some images:

- -
- - -
- -
-
- -
-
- -
-
- -
- - - - - - + +

and here's a demonstration with some images:

+ +
+ + +
+
- -

jParallax also provides options and event bindings that give you control over a layer's behaviour. We all like tweaky-tweaky.

- -

More demos

-
    +
    + +
    +
    + +
    +
    + +
    + + + + + + +
+ +

jParallax also provides options and event bindings that give you control over a layer's behaviour. We all like + tweaky-tweaky.

+ +

More demos

+ - -

Using jParallax

-

The default behaviour of jParallax is to show the whole width of a layer in response to the mouse travelling the whole width of the mouseport. When the mouse is moved to the extreme left-hand side of the mouseport the left-hand side of the layer meets the left-hand side of its viewport, and when the mouse is moved to the extreme right-hand side of the mouseport the right-hand side of the layer arrives at the right hand-side of its viewport.

-

Therefore, the simplest way to use jParallax is to make the layers different sizes using CSS. Bigger layers move faster (and thus appear closer), and unless a layer is smaller than the viewport, its edges are never seen. The Colour Drops Demo is made in exactly this way, with jParallax in its default state, and the 'speed' of the layers controlled simply by making the images different sizes. Only the mouseport option is defined, to make it the same as the viewport.

- -

CSS

-

There are various ways to style jParallax effectively. The classic approach is the 'viewport' effect, as in the example above. To see layers through a viewport, wrap them in a container with a style similar to:

+
  • demos/target.html - demonstrates how smoothly jParallax handles window resizing. +
  • + + +

    Using jParallax

    + +

    The default behaviour of jParallax is to show the whole width of a layer in response to the mouse travelling the + whole width of the mouseport. When the mouse is moved to the extreme left-hand side of the mouseport the left-hand + side of the layer meets the left-hand side of its viewport, and when the mouse is moved to the extreme right-hand + side of the mouseport the right-hand side of the layer arrives at the right hand-side of its viewport.

    + +

    Therefore, the simplest way to use jParallax is to make the layers different sizes using CSS. Bigger layers move + faster (and thus appear closer), and unless a layer is smaller than the viewport, its edges are never seen. The Colour Drops Demo is made in exactly this way, with jParallax in its default + state, and the 'speed' of the layers controlled simply by making the images different sizes. Only the mouseport + option is defined, to make it the same as the viewport.

    + +

    CSS

    + +

    There are various ways to style jParallax effectively. The classic approach is the 'viewport' effect, as in the + example above. To see layers through a viewport, wrap them in a container with a style similar to:

    .parallax-viewport
    -    { position:relative; overflow:hidden; width:npx; height:npx; }
    -

    The position declaration sets up the viewport as an offset parent for the layers, while overflow:hidden; stops them being visible outside its boundaries. In order for the layers to respond, they must be given:

    + { position:relative; overflow:hidden; width:npx; height:npx; }
    +

    The position declaration sets up the viewport as an offset parent for the layers, while overflow:hidden; + stops them being visible outside its boundaries. In order for the layers to respond, they must be given:

    .parallax-layer
         { position:absolute; }
    -

    There is a basic stylesheet included with the download that provides these classes, and the demos are a good reference for some other effects you can achieve.

    +

    There is a basic stylesheet included with the download that provides these classes, and the demos are a good reference for some other effects you can achieve.

    Options

    - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionTypeDefault
    OptionTypeDefault
    mouseportselector string | jQuery objectjQuery(document)
    Identifies DOM node to track the mouse in.
    xparallaxboolean | 0-1 | 'n%' | 'npx'true
    yparallaxboolean | 0-1 | 'n%' | 'npx'true
    Set to true or false to enable or disable movement. Alternatively, to control the range over which a layer travels, either pass in an absolute value in pixels, or a scaling factor in the range 0-1 (scaling factors can also be expressed as percentage strings). Scaling factors outside this range are also accepted, but be aware that factors below 0 (or '0%') will reverse the direction of travel, and greater than 1 (or '100%') will make layer edges appear inside the extremes of the viewport.
    xorigin0-1 | 'n%' | 'left', 'center', 'middle', 'right'0.5
    yorigin0-1 | 'n%' | 'top', 'center', 'middle'. 'bottom'0.5
    Only meaningful when xparallax or yparallax are not 1. Determines which point of the layer lines up with which point of the viewport when the mouse is at that point in the mouseport. Got that?

    It's easy really. It's the same behaviour as the css property background-position. If xorigin is set to 0 (or 'left'), then when the mouse is moved to the left hand side of the mouseport the left hand side of the layer arrives at the left hand side of the viewport. If it's set to 0.5 (or 'center'), then when the mouse is at the centre of the mouseport the centre of the layer is aligned with the centre of the viewport. And similarly with 1 (or 'right').

    -Numbers outside the range 0-1 may also be used.
    freezeClassstring'freeze'
    Class set on a layer when it is frozen.
    decay0-10.66
    Sets the rate at which the layers 'catch up' with the mouse position. 0 is instantly, 1 is forever.
    frameDurationint (milliseconds)30
    Length of time between animation frames. With a lot of big layers, you may want to increase the frame duration to save CPU. About 50 is acceptable (20 frames/second), but I like it zippy. Modern browsers like Google Chrome have really accurate timing, but many older browsers choke below about 15ms.
    widthint (px)undefined
    heightint (px)undefined
    Values for layer dimensions, normally read from css, can be overridden. This does NOT change the css, only jParallax's idea of how big a layer is. This can be very useful in cases where you want to be able to 'click through' the upper layers. Typically you make layers very small in css, but tell jParallax they are big via width and height. You prabably want overflow: visible on those layers, too.
    mouseportselector string | jQuery objectjQuery(document)
    Identifies DOM node to track the mouse in.
    xparallaxboolean | 0-1 | 'n%' | 'npx'true
    yparallaxboolean | 0-1 | 'n%' | 'npx'true
    Set to true or false to enable or disable movement. Alternatively, to control the + range over which a layer travels, either pass in an absolute value in pixels, or a scaling factor in the + range 0-1 (scaling factors can also be expressed as percentage strings). Scaling factors outside this range + are also accepted, but be aware that factors below 0 (or '0%') will reverse the direction of travel, and + greater than 1 (or '100%') will make layer edges appear inside the extremes of the viewport. +
    xorigin0-1 | 'n%' | 'left', 'center', 'middle', 'right'0.5
    yorigin0-1 | 'n%' | 'top', 'center', 'middle'. 'bottom'0.5
    Only meaningful when xparallax or yparallax are not 1. Determines which point of + the layer lines up with which point of the viewport when the mouse is at that point in the mouseport. Got + that?

    It's easy really. It's the same behaviour as the css property + background-position. If xorigin is set to 0 (or 'left'), then + when the mouse is moved to the left hand side of the mouseport the left hand side of the layer arrives at + the left hand side of the viewport. If it's set to 0.5 (or 'center'), then + when the mouse is at the centre of the mouseport the centre of the layer is aligned with the centre of the + viewport. And similarly with 1 (or 'right').

    + Numbers outside the range 0-1 may also be used. +
    freezeClassstring'freeze'
    Class set on a layer when it is frozen.
    decay0-10.66
    Sets the rate at which the layers 'catch up' with the mouse position. 0 is + instantly, 1 is forever. +
    frameDurationint (milliseconds)30
    Length of time between animation frames. With a lot of big layers, you may want to + increase the frame duration to save CPU. About 50 is acceptable (20 frames/second), but I like it zippy. + Modern browsers like Google Chrome have really accurate timing, + but many older browsers choke below about 15ms. +
    widthint (px)undefined
    heightint (px)undefined
    Values for layer dimensions, normally read from css, can be overridden. This does + NOT change the css, only jParallax's idea of how big a layer is. This can be very useful in cases where you + want to be able to 'click through' the upper layers. Typically you make layers very small in css, but tell + jParallax they are big via width and height. You prabably want overflow: visible on those layers, too. +
    -

    Layer Options

    -

    In addition to the global options above, individual layers can be passed their own set of options as extra arguments:

    - -
    jQuery('.parallax-layer').parallax(options, layer_0_options, layer_1_options, ... );
    - -

    As an example, to give the second layer a set xtravel value, but pass no options as default:

    - -
    jQuery('.parallax-layer').parallax({}, {}, {xtravel: '200px'});
    - -

    A layer option object can have the properties xparallax, yparallax, xorigin, yorigin, width and height, with the same meanings as described above.

    +

    Layer Options

    + +

    In addition to the global options above, individual layers can be passed their own set of options as extra + arguments:

    + +
    jQuery('.parallax-layer').parallax(options, layer_0_options, layer_1_options, ... );
    + +

    As an example, to give the second layer a set xtravel value, but pass no options as default:

    -

    Events

    -

    Events can be triggered on layers using jQuery's trigger method:

    -
    jQuery( '.parallax-layer' ).trigger({ type: 'freeze' });
    +
    jQuery('.parallax-layer').parallax({}, {}, {xtravel: '200px'});
    + +

    A layer option object can have the properties xparallax, yparallax, xorigin, yorigin, width and height, with the same + meanings as described above.

    + +

    Events

    + +

    Events can be triggered on layers using jQuery's trigger method:

    +
    jQuery( '.parallax-layer' ).trigger({ type: 'freeze' });
    - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + + +
    EventEvent object
    EventEvent object
    freeze{ type: 'freeze', x: 0-1, y: 0-1, decay: 0-1 }
    Stops the layer from moving. Use the optional event object properties to send the layer to a specific position: x and y tell a layer where to go (expressed as a ratio of the width of the viewport in the range 0-1), and decay how fast to go there ( where 0 is immediate and 1 is forever ). When the layer comes to rest the class 'freeze' is given to the layer. freezeClass is setable in the options object.
    unfreeze{ type: 'unfreeze' }
    Should be 'thaw', I suppose, really. That sounds weird, though. Unfreeze sets the layer in motion again.
    freeze{ type: 'freeze', x: 0-1, y: 0-1, decay: 0-1 }
    Stops the layer from moving. Use the optional event object properties to send the layer to a + specific position: x and y tell a layer where to go (expressed as a ratio of the + width of the viewport in the range 0-1), and decay how fast to go there ( where 0 is immediate + and 1 is forever ). When the layer comes to rest the class 'freeze' is given to the layer. + freezeClass is setable in the options object. +
    unfreeze{ type: 'unfreeze' }
    Should be 'thaw', I suppose, really. That sounds weird, though. Unfreeze sets the layer in + motion again. +
    -

    Some sites using jParallax

    - +

    Let me know if you have a site that uses jParallax - 'Write to me' form at the top of this page.

    -

    Tips

    - -

    Transparent image layers

    -

    Lots of transparency in images will slow down a browser's ability to render quickly. Avoid making huge layers of semi-opaque graphics if you don't want lesser browsers to choke.

    -

    Try jQuery iFixPng plugin, to make see-through .png images work on IE6.

    +

    Tips

    + +

    Transparent image layers

    + +

    Lots of transparency in images will slow down a browser's ability to render quickly. Avoid making huge layers of + semi-opaque graphics if you don't want lesser browsers to choke.

    -

    Version history

    -

    See the changelog.

    -

    Bug reporting

    -

    http://cloud.github.com/downloads/stephband/jparallax/

    +

    Try jQuery iFixPng plugin, to make see-through .png images + work on IE6.

    + +

    Version history

    + +

    See the changelog.

    + +

    Bug reporting

    + +

    http://cloud.github.com/downloads/stephband/jparallax/

    - Write me - Buy me beer -
    - -
    - - - - -
    -
    + Write me + Buy me beer + +
    + +
    + + + + +
    +
    @@ -356,64 +511,70 @@

    Bug reporting

    diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index acd3c27..b1f9908 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -334,15 +334,12 @@ function Layer(elem, options){ // EVENT HANDLERS -function update(e){ +function update(e, data){ if (window.DeviceMotionEvent) { var elem = $(this), local = elem.data(plugin); - e.forEach(function (val, key) { - console.log(key, val); - }); - //local.layer.update([e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y]); + local.layer.update([data.accelerationIncludingGravity.x, data.accelerationIncludingGravity.y]); } else { var elem = $(this), global = e.data, @@ -508,10 +505,29 @@ $.fn[plugin] = function(o){ var self = this; window.addEventListener('devicemotion', function (e) { - layers.trigger('DeviceMotionEvent', e); + layers.trigger('DeviceMotionEvent', { + accelerationIncludingGravity: { + x: Math.round(e.accelerationIncludingGravity.x) / 10, + y: Math.round(e.accelerationIncludingGravity.y) / 10 + } + }); }, false); - return layers.on('DeviceMotionEvent', global, update); + return layers.on('DeviceMotionEvent', global, update) + .each(function(i){ + var elem = $(this), + + // Construct layer options from extra arguments + layerOptions = args[i+1] ? $.extend({}, global, args[i+1]) : global , + layer = new Layer(elem, layerOptions); + + // Set up layer data. Give it a local mouse + // initialises it to start smoothly from current position + elem.data(plugin, { + layer: layer, + mouse: new Mouse(layerOptions, layer.getPointer()) + }); + }); } }; From f19af6bb4253d9e522060530f4525d6bb25809f5 Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Thu, 12 Apr 2012 21:32:04 +0200 Subject: [PATCH 6/9] Some more stable code Sorry for reformating code --- js/jquery.jparallax.js | 930 +++++++++++++++++++++-------------------- 1 file changed, 476 insertions(+), 454 deletions(-) diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index b1f9908..9878e3d 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -12,524 +12,546 @@ // $.event.frame // webdev.stephband.info/events/frame/ -(function($) { +(function ($) { // Plugin name -var plugin = "parallax"; + var plugin = "parallax"; // VAR -var options = { - mouseport: 'body', // jQuery object or selector of DOM node to use as mouse detector - xparallax: true, // boolean | 0-1 | 'npx' | 'n%' - Sets axis of reaction and by how much they react - yparallax: true, // - xorigin: 0.5, // 0-1 - Sets default alignment. Only has effect when parallax values are something other than 1 (or true, or '100%') - yorigin: 0.5, // - decay: 0.66, // 0-1 (0 instant, 1 forever) - Sets rate of decay curve for catching up with target mouse position - frameDuration: 30, // Int (milliseconds) - freezeClass: 'freeze' // String - Class added to layer when frozen - }, - value = { - left: 0, - top: 0, - middle: 0.5, - center: 0.5, - right: 1, - bottom: 1 - }, - regex = { - px: /^\d+\s?px$/, - percent: /^\d+\s?%$/ - }, - frameEvent = 'frame.'+plugin, - abs = Math.abs, - pointer = [0, 0]; + var options = { + mouseport:'body', // jQuery object or selector of DOM node to use as mouse detector + xparallax:true, // boolean | 0-1 | 'npx' | 'n%' - Sets axis of reaction and by how much they react + yparallax:true, // + xorigin:0.5, // 0-1 - Sets default alignment. Only has effect when parallax values are something other than 1 (or true, or '100%') + yorigin:0.5, // + decay:0.66, // 0-1 (0 instant, 1 forever) - Sets rate of decay curve for catching up with target mouse position + frameDuration:30, // Int (milliseconds) + freezeClass:'freeze' // String - Class added to layer when frozen + }, + value = { + left:0, + top:0, + middle:0.5, + center:0.5, + right:1, + bottom:1 + }, + regex = { + px:/^\d+\s?px$/, + percent:/^\d+\s?%$/ + }, + frameEvent = 'frame.' + plugin, + abs = Math.abs, + pointer = [0, 0]; // FUNCTIONS -function parseValue(value) { return this.lib[value]; } -parseValue.lib = value; + function parseValue(value) { + return this.lib[value]; + } + + parseValue.lib = value; // Converts numbers or numbers in strings to boolean -function parseBool(x) { - return typeof x === "boolean" ? x : !!( parseFloat(x) ) ; -} + function parseBool(x) { + return typeof x === "boolean" ? x : !!( parseFloat(x) ); + } -function parseCoord(x) { - return (regex.percent.exec(x)) ? parseFloat(x)/100 : x; -} + function parseCoord(x) { + return (regex.percent.exec(x)) ? parseFloat(x) / 100 : x; + } // CONSTRUCTORS -function Mouse(options, pointer){ - - // Convert parallax options to boolean values - var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; - - this.ontarget = false; - this.decay = options.decay; - this.pointer = pointer || [0.5, 0.5]; - this.update = function(pointer, threshold){ - - // Pointer is already on target - if (this.ontarget) { - this.pointer = pointer; - } - - // Pointer has arrived within the target thresholds - else if ( (!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && - (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1]) ) { - - this.ontarget = true; - this.pointer = pointer; - } - - // Pointer is nowhere near the target - else { - var lagPointer = [], - x = 2; - - while (x--) { - if ( parallax[x] ) { - lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]) ; + function Mouse(options, pointer) { + + // Convert parallax options to boolean values + var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; + + this.ontarget = false; + this.decay = options.decay; + this.pointer = pointer || [0.5, 0.5]; + this.update = function (pointer, threshold) { + + // Pointer is already on target + if (this.ontarget) { + this.pointer = pointer; + } + + // Pointer has arrived within the target thresholds + else if ((!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && + (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1])) { + + this.ontarget = true; + this.pointer = pointer; + } + + // Pointer is nowhere near the target + else { + var lagPointer = [], + x = 2; + + while (x--) { + if (parallax[x]) { + lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]); + } } + this.pointer = lagPointer; } - this.pointer = lagPointer; - } - }; -} + }; + } -function DeviceMotion(options, pointer){ + function DeviceMotion(options, pointer) { - // Convert parallax options to boolean values - var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; + // Convert parallax options to boolean values + var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; - this.ontarget = false; - this.decay = options.decay; - this.pointer = pointer || [0.5, 0.5]; - this.update = function(pointer, threshold){ + this.ontarget = false; + this.decay = options.decay; + this.pointer = pointer || [0.5, 0.5]; + this.update = function (pointer, threshold) { - // Pointer is already on target - if (this.ontarget) { - this.pointer = pointer; - } + // Pointer is already on target + if (this.ontarget) { + this.pointer = pointer; + } - // Pointer has arrived within the target thresholds - else if ( (!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && - (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1]) ) { + // Pointer has arrived within the target thresholds + else if ((!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && + (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1])) { - this.ontarget = true; - this.pointer = pointer; - } + this.ontarget = true; + this.pointer = pointer; + } - // Pointer is nowhere near the target - else { - var lagPointer = [], - x = 2; + // Pointer is nowhere near the target + else { + var lagPointer = [], + x = 2; - while (x--) { - if ( parallax[x] ) { - lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]) ; + while (x--) { + if (parallax[x]) { + lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]); + } } + this.pointer = lagPointer; } - this.pointer = lagPointer; - } - }; -} + }; + } -function Port(object, options){ - var self = this, - elem = object instanceof $ ? object : $(object) , + function Port(object, options) { + var self = this, + elem = object instanceof $ ? object : $(object) , // Convert parallax options to boolean values - parallax = [parseBool(options.xparallax), parseBool(options.yparallax)], + parallax = [parseBool(options.xparallax), parseBool(options.yparallax)], // State of mouse position (0 - outside, 1 - inside, 2 - just gone outside) - inside = 0, + inside = 0, // Stores mouse position on mouseleave event - leaveCoords; - - this.pointer = [0, 0]; - this.active = false; - this.activeOutside = (options && options.activeOutside) || false; - this.update = function(coords){ - var pos = this.pos, - size = this.size, - pointer = [], - x = 2; - - // Is mouse inside port? - // Yes. - if ( inside > 0 ) { - // But it just went outside, so make this the last move - // Use leaveCoords stored by mouseleave event - if ( inside === 2 ) { - inside = 0; - if (leaveCoords) { - coords = leaveCoords - }; - } - - while (x--) { - if ( parallax[x] ) { - pointer[x] = (coords[x] - pos[x]) / size[x] ; - pointer[x] = pointer[x] < 0 ? 0 : pointer[x] > 1 ? 1 : pointer[x] ; - } - } - - this.active = true; - this.pointer = pointer; - } - // No. - else { - this.active = false; - } - }; - this.updateSize = function(){ - var width = elem.width(), - height = elem.height(); - - self.size = [width, height]; - self.threshold = [ 1/width, 1/height ]; - }; - this.updatePos = function(){ - var offset = elem.offset() || {left: 0, top: 0}, - left = parseInt(elem.css('borderLeftWidth')) + parseInt(elem.css('paddingLeft')), - top = parseInt(elem.css('borderTopWidth')) + parseInt(elem.css('paddingTop')); - - self.pos = [offset.left + left, offset.top + top]; - }; - - // Update mouseport dimensions on window resize - $(window) - .on('resize.'+plugin, self.updateSize) - .on('resize.'+plugin, self.updatePos); - - // Detect entry and exit of mouse - elem - .on('mouseenter.'+plugin, function(e){ - inside = 1; - }) - .on('mouseleave.'+plugin, function(e){ - inside = 2; - leaveCoords = [e.pageX, e.pageY]; - }); - - // Set up layer - this.updateSize(); - this.updatePos(); -} - -function Layer(elem, options){ - var px = [], - parallax = [], - offset = [], - position = []; - - this.update = function(pointer){ - var pos = [], - cssPosition, - cssMargin, - x = 2, - css = {}; - - while (x--) { - if ( parallax[x] ) { - pos[x] = parallax[x] * pointer[x] + offset[x]; - - // We're working in pixels - if ( px[x] ) { - cssPosition = position[x]; - cssMargin = pos[x] * -1; - } - // We're working by ratio - else { - cssPosition = pos[x] * 100 + '%'; - cssMargin = pos[x] * this.size[x] * -1; - } - - // Fill in css object - if ( x === 0 ) { - css.left = cssPosition; - css.marginLeft = cssMargin; + leaveCoords; + + this.pointer = [0, 0]; + this.active = false; + this.activeOutside = (options && options.activeOutside) || false; + this.update = function (coords) { + var pos = this.pos, + size = this.size, + pointer = [], + x = 2; + + // Is mouse inside port? + // Yes. + if (inside > 0) { + // But it just went outside, so make this the last move + // Use leaveCoords stored by mouseleave event + if (inside === 2) { + inside = 0; + if (leaveCoords) { + coords = leaveCoords + } + ; } - else { - css.top = cssPosition; - css.marginTop = cssMargin; + + while (x--) { + if (parallax[x]) { + pointer[x] = (coords[x] - pos[x]) / size[x]; + pointer[x] = pointer[x] < 0 ? 0 : pointer[x] > 1 ? 1 : pointer[x]; + } } - } - } - - // Set css - elem.css(css); - }; - this.setParallax = function(xp, yp, xo, yo){ - var p = [ xp || options.xparallax, yp || options.yparallax ], - origin = [ xo || options.xorigin, yo || options.yorigin ], - i = 2, - css = {}; - - while (i--) { - // Set px flag - px[i] = regex.px.test(p[i]); - - // Convert origin to numbers - if (typeof origin[i] === 'string') { - origin[i] = origin[i] === undefined ? 1 : - value[ origin[i] ] || parseCoord(origin[i]) ; + this.active = true; + this.pointer = pointer; } - - // We're dealing with pixel dimensions - if ( px[i] ) { - // Set parallax - parallax[i] = parseInt(p[i]); - - // Set offset - offset[i] = origin[i] * ( this.size[i] - parallax[i] ); - - // Set css position constant - position[i] = origin[i] * 100 + '%'; - } - - // We're dealing with ratios + // No. else { - // Set parallax, converting to ratio where necessary - parallax[i] = p[i] === true ? 1 : parseCoord(p[i]); - - // Set offset - offset[i] = parallax[i] ? origin[i] * ( 1 - parallax[i] ) : 0 ; + this.active = false; } - } - }; + }; + this.updateSize = function () { + var width = elem.width(), + height = elem.height(); + + self.size = [width, height]; + self.threshold = [ 1 / width, 1 / height ]; + }; + this.updatePos = function () { + var offset = elem.offset() || {left:0, top:0}, + left = parseInt(elem.css('borderLeftWidth')) + parseInt(elem.css('paddingLeft')), + top = parseInt(elem.css('borderTopWidth')) + parseInt(elem.css('paddingTop')); + + self.pos = [offset.left + left, offset.top + top]; + }; + + // Update mouseport dimensions on window resize + $(window) + .on('resize.' + plugin, self.updateSize) + .on('resize.' + plugin, self.updatePos); + + // Detect entry and exit of mouse + elem + .on('mouseenter.' + plugin, function (e) { + inside = 1; + }) + .on('mouseleave.' + plugin, function (e) { + inside = 2; + leaveCoords = [e.pageX, e.pageY]; + }); - this.getPointer = function(){ - var viewport = elem.offsetParent(), - pos = elem.position(), - position = [], - pointer = [], - i = 2; - - // Reverse calculate ratio from layer's current position - while (i--) { - if ( px[i] ) { - // TODO: reverse calculation for pixel case - position[i] = 0; - } - else { - position[i] = pos[ i === 0 ? 'left' : 'top' ] / (viewport[ i === 0 ? 'outerWidth' : 'outerHeight' ]() - this.size[i]) ; - } - - pointer[i] = (position[i] - offset[i]) / parallax[i] ; - } - - return pointer; - }; + // Set up layer + this.updateSize(); + this.updatePos(); + } - this.setSize = function(x, y){ - this.size = [ x || elem.outerWidth(), y || elem.outerHeight() ]; - }; - - this.setSize(options.width, options.height); - this.setParallax(options.xparallax, options.yparallax, options.xorigin, options.yorigin); -} + function Layer(elem, options) { + var px = [], + parallax = [], + offset = [], + position = []; -// EVENT HANDLERS + this.update = function (pointer) { + var pos = [], + cssPosition, + cssMargin, + x = 2, + css = {}; -function update(e, data){ - if (window.DeviceMotionEvent) { - var elem = $(this), - local = elem.data(plugin); - - local.layer.update([data.accelerationIncludingGravity.x, data.accelerationIncludingGravity.y]); - } else { - var elem = $(this), - global = e.data, - local = elem.data(plugin), - port = global.port, - mouse = global.mouse, - localmouse = local.mouse, - process = global.timeStamp !== e.timeStamp; - - // Global objects have yet to be processed for this frame - if ( process ) { - // Set timeStamp to current time - global.timeStamp = e.timeStamp; - - // Process mouseport - port.update(pointer); - - // Process mouse - if ( port.active || !mouse.ontarget ) { - mouse.update(port.pointer, port.threshold); + while (x--) { + if (parallax[x]) { + pos[x] = parallax[x] * pointer[x] + offset[x]; + + // We're working in pixels + if (px[x]) { + cssPosition = position[x]; + cssMargin = pos[x] * -1; + } + // We're working by ratio + else { + cssPosition = pos[x] * 100 + '%'; + cssMargin = pos[x] * this.size[x] * -1; + } + + // Fill in css object + if (x === 0) { + css.left = cssPosition; + css.marginLeft = cssMargin; + } + else { + css.top = cssPosition; + css.marginTop = cssMargin; + } + } } - } - - // Layer has it's own mouse - if ( localmouse ) { - // Process mouse - localmouse.update( local.freeze ? local.freeze.pointer : port.pointer, port.threshold ); + // Set css + elem.css(css); + }; - // If it hits target - if ( localmouse.ontarget ) { + this.setParallax = function (xp, yp, xo, yo) { + var p = [ xp || options.xparallax, yp || options.yparallax ], + origin = [ xo || options.xorigin, yo || options.yorigin ], + i = 2, + css = {}; - delete local.mouse; + while (i--) { + // Set px flag + px[i] = regex.px.test(p[i]); - // Stop animating frozen layers - if (local.freeze) { - elem - .off(frameEvent) - .addClass(global.freezeClass); + // Convert origin to numbers + if (typeof origin[i] === 'string') { + origin[i] = origin[i] === undefined ? 1 : + value[ origin[i] ] || parseCoord(origin[i]); } - } - // Use localmouse in place of mouse - mouse = localmouse; - } - // Layer is responding to global mouse - else { - // When no longer active, unbind - if ( mouse.ontarget && !port.active ) { - elem.off(frameEvent); - } - } + // We're dealing with pixel dimensions + if (px[i]) { + // Set parallax + parallax[i] = parseInt(p[i]); - local.layer.update(mouse.pointer); - } -} + // Set offset + offset[i] = origin[i] * ( this.size[i] - parallax[i] ); -$.fn[plugin] = function(o){ - if (undefined === $.event.special.frame) { - throw "$.event.frame is required for jparallax to work" - } + // Set css position constant + position[i] = origin[i] * 100 + '%'; + } - var global = $.extend({}, $.fn[plugin].options, o), - args = arguments, - layers = this; + // We're dealing with ratios + else { + // Set parallax, converting to ratio where necessary + parallax[i] = p[i] === true ? 1 : parseCoord(p[i]); - if (window.DeviceMotionEvent) { - global.DeviceMotionEvent = true; - } else { - global.DeviceMotionEvent = false; - } + // Set offset + offset[i] = parallax[i] ? origin[i] * ( 1 - parallax[i] ) : 0; + } + } + }; + + this.getPointer = function () { + var viewport = elem.offsetParent(), + pos = elem.position(), + position = [], + pointer = [], + i = 2; + + // Reverse calculate ratio from layer's current position + while (i--) { + if (px[i]) { + // TODO: reverse calculation for pixel case + position[i] = 0; + } + else { + position[i] = pos[ i === 0 ? 'left' : 'top' ] / (viewport[ i === 0 ? 'outerWidth' : 'outerHeight' ]() - this.size[i]); + } - if (global.DeviceMotionEvent === false) { - // Turn mouseport into $ obj - if ( !(global.mouseport instanceof $) ) { - global.mouseport = $(global.mouseport); - } + pointer[i] = (position[i] - offset[i]) / parallax[i]; + } - global.port = new Port(global.mouseport, global); - global.mouse = new Mouse(global); + return pointer; + }; - global.mouseport - .on("mouseenter", function(e){ - global.mouse.ontarget = false; - // Animate unfrozen layers - layers - .each(function(i){ - var layer = $(this); + this.setSize = function (x, y) { + this.size = [ x || elem.outerWidth(), y || elem.outerHeight() ]; + }; - if ( !layer.data(plugin).freeze ) { - layer - .on(frameEvent, global, update); - } - }); - }); + this.setSize(options.width, options.height); + this.setParallax(options.xparallax, options.yparallax, options.xorigin, options.yorigin); + } - return layers - .on("freeze", function(e){ +// EVENT HANDLERS + + function update(e, data) { + if (window.DeviceMotionEvent && (navigator.userAgent.match(/Android/i) + || navigator.userAgent.match(/webOS/i) + || navigator.userAgent.match(/iPhone/i) + || navigator.userAgent.match(/iPad/i) + || navigator.userAgent.match(/iPod/i))) { var elem = $(this), - local = elem.data(plugin), - mouse = local.mouse || local.freeze || global.mouse, - coords = coords = [ - e.x === undefined ? mouse.pointer[0] : parseCoord(e.x), - e.y === undefined ? mouse.pointer[1] : parseCoord(e.y) - ], - decay = e.decay; - - // Store position - local.freeze = { - pointer: coords - }; - - // Create local mouse, passing in current pointer with options - local.mouse = new Mouse(global, mouse.pointer); - - if (decay !== undefined) { - local.mouse.decay = decay; - }; - - // Start animating - elem.on(frameEvent, global, update); - }) - .on("unfreeze", function(e){ + local = elem.data(plugin); + + local.layer.update([data.accelerationIncludingGravity.x, data.accelerationIncludingGravity.y]); + } else { var elem = $(this), + global = e.data, local = elem.data(plugin), - decay = e.decay, - pointer; + port = global.port, + mouse = global.mouse, + localmouse = local.mouse, + process = global.timeStamp !== e.timeStamp; + + // Global objects have yet to be processed for this frame + if (process) { + // Set timeStamp to current time + global.timeStamp = e.timeStamp; + + // Process mouseport + port.update(pointer); + + // Process mouse + if (port.active || !mouse.ontarget) { + mouse.update(port.pointer, port.threshold); + } + } + + // Layer has it's own mouse + if (localmouse) { - if (local.freeze) { + // Process mouse + localmouse.update(local.freeze ? local.freeze.pointer : port.pointer, port.threshold); - // Create local mouse, passing local freeze pointer with options - pointer = local.mouse ? local.mouse.pointer : local.freeze.pointer ; - local.mouse = new Mouse(global); - local.mouse.pointer = pointer; + // If it hits target + if (localmouse.ontarget) { - // Override decay with decay passed as e.decay - if (decay !== undefined) local.mouse.decay = decay; + delete local.mouse; - // Destroy local.freeze - delete local.freeze; + // Stop animating frozen layers + if (local.freeze) { + elem + .off(frameEvent) + .addClass(global.freezeClass); + } + } - // Remove freeze class and start animating - elem - .removeClass(options.freezeClass) - .on(frameEvent, global, update); + // Use localmouse in place of mouse + mouse = localmouse; + } + // Layer is responding to global mouse + else { + // When no longer active, unbind + if (mouse.ontarget && !port.active) { + elem.off(frameEvent); + } } - }) - .each(function(i){ - var elem = $(this), - // Construct layer options from extra arguments - layerOptions = args[i+1] ? $.extend({}, global, args[i+1]) : global , - layer = new Layer(elem, layerOptions); + local.layer.update(mouse.pointer); + } + } - // Set up layer data. Give it a local mouse - // initialises it to start smoothly from current position - elem.data(plugin, { - layer: layer, - mouse: new Mouse(layerOptions, layer.getPointer()) - }); - }); - } else { - var self = this; - - window.addEventListener('devicemotion', function (e) { - layers.trigger('DeviceMotionEvent', { - accelerationIncludingGravity: { - x: Math.round(e.accelerationIncludingGravity.x) / 10, - y: Math.round(e.accelerationIncludingGravity.y) / 10 - } - }); - }, false); + $.fn[plugin] = function (o) { + if (undefined === $.event.special.frame) { + throw "$.event.frame is required for jparallax to work" + } - return layers.on('DeviceMotionEvent', global, update) - .each(function(i){ - var elem = $(this), + var global = $.extend({}, $.fn[plugin].options, o), + args = arguments, + layers = this; + + if (window.DeviceMotionEvent && (navigator.userAgent.match(/Android/i) + || navigator.userAgent.match(/webOS/i) + || navigator.userAgent.match(/iPhone/i) + || navigator.userAgent.match(/iPad/i) + || navigator.userAgent.match(/iPod/i))) { + global.DeviceMotionEvent = true; + } else { + global.DeviceMotionEvent = false; + } - // Construct layer options from extra arguments - layerOptions = args[i+1] ? $.extend({}, global, args[i+1]) : global , - layer = new Layer(elem, layerOptions); + if (global.DeviceMotionEvent === false) { + // Turn mouseport into $ obj + if (!(global.mouseport instanceof $)) { + global.mouseport = $(global.mouseport); + } - // Set up layer data. Give it a local mouse - // initialises it to start smoothly from current position - elem.data(plugin, { - layer: layer, - mouse: new Mouse(layerOptions, layer.getPointer()) + global.port = new Port(global.mouseport, global); + global.mouse = new Mouse(global); + + global.mouseport + .on("mouseenter", function (e) { + global.mouse.ontarget = false; + // Animate unfrozen layers + layers + .each(function (i) { + var layer = $(this); + + if (!layer.data(plugin).freeze) { + layer + .on(frameEvent, global, update); + } + }); }); - }); - } -}; + + return layers + .on("freeze", function (e) { + var elem = $(this), + local = elem.data(plugin), + mouse = local.mouse || local.freeze || global.mouse, + coords = coords = [ + e.x === undefined ? mouse.pointer[0] : parseCoord(e.x), + e.y === undefined ? mouse.pointer[1] : parseCoord(e.y) + ], + decay = e.decay; + + // Store position + local.freeze = { + pointer:coords + }; + + // Create local mouse, passing in current pointer with options + local.mouse = new Mouse(global, mouse.pointer); + + if (decay !== undefined) { + local.mouse.decay = decay; + } + + // Start animating + elem.on(frameEvent, global, update); + }) + .on("unfreeze", function (e) { + var elem = $(this), + local = elem.data(plugin), + decay = e.decay, + pointer; + + if (local.freeze) { + + // Create local mouse, passing local freeze pointer with options + pointer = local.mouse ? local.mouse.pointer : local.freeze.pointer; + local.mouse = new Mouse(global); + local.mouse.pointer = pointer; + + // Override decay with decay passed as e.decay + if (decay !== undefined) local.mouse.decay = decay; + + // Destroy local.freeze + delete local.freeze; + + // Remove freeze class and start animating + elem + .removeClass(options.freezeClass) + .on(frameEvent, global, update); + } + }) + .each(function (i) { + var elem = $(this), + + // Construct layer options from extra arguments + layerOptions = args[i + 1] ? $.extend({}, global, args[i + 1]) : global , + layer = new Layer(elem, layerOptions); + + // Set up layer data. Give it a local mouse + // initialises it to start smoothly from current position + elem.data(plugin, { + layer:layer, + mouse:new Mouse(layerOptions, layer.getPointer()) + }); + }); + } else { + var self = this; + + window.addEventListener('devicemotion', function (e) { + var acceleration = e.accelerationIncludingGravity; + + var facingUp = -1; + if (acceleration.z > 0) { + facingUp = +1; + } + + var tiltLR = Math.round(((acceleration.x) / 9.81) * -90); + var tiltFB = Math.round(((acceleration.y + 9.81) / 9.81) * 90 * facingUp); + + layers.trigger('DeviceMotionEvent', { + accelerationIncludingGravity:{ + x:tiltLR / 100, + y:tiltFB / 100 + } + }); + }, false); + + return layers.on('DeviceMotionEvent', global, update) + .each(function (i) { + var elem = $(this), + layerOptions = args[i + 1] ? $.extend({}, global, args[i + 1]) : global , + layer = new Layer(elem, layerOptions); + + elem.css({left: ((elem.width() - $(global.mouseport).width()) / 2) * -1}); + + // Set up layer data. Give it a local mouse + // initialises it to start smoothly from current position + elem.data(plugin, { + layer:layer, + mouse:new Mouse(layerOptions, layer.getPointer()) + }); + }); + } + }; // EXPOSE @@ -537,13 +559,13 @@ $.fn[plugin] = function(o){ // RUN -$(document).ready(function(){ - // Pick up and store mouse position on $(document) - // IE does not register mousemove on $(window) - $(document) - .mousemove(function(e){ - pointer = [e.pageX, e.pageY]; + $(document).ready(function () { + // Pick up and store mouse position on $(document) + // IE does not register mousemove on $(window) + $(document) + .mousemove(function (e) { + pointer = [e.pageX, e.pageY]; + }); }); -}); }(jQuery)); \ No newline at end of file From 01b76c359d3083a94089c10a9f1fd6db78fdfd5b Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Thu, 12 Apr 2012 21:32:26 +0200 Subject: [PATCH 7/9] Removed unused code --- js/jquery.jparallax.js | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index 9878e3d..db3f6a2 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -102,44 +102,6 @@ }; } - function DeviceMotion(options, pointer) { - - // Convert parallax options to boolean values - var parallax = [ parseBool(options.xparallax), parseBool(options.yparallax) ]; - - this.ontarget = false; - this.decay = options.decay; - this.pointer = pointer || [0.5, 0.5]; - this.update = function (pointer, threshold) { - - // Pointer is already on target - if (this.ontarget) { - this.pointer = pointer; - } - - // Pointer has arrived within the target thresholds - else if ((!parallax[0] || abs(pointer[0] - this.pointer[0]) < threshold[0]) && - (!parallax[1] || abs(pointer[1] - this.pointer[1]) < threshold[1])) { - - this.ontarget = true; - this.pointer = pointer; - } - - // Pointer is nowhere near the target - else { - var lagPointer = [], - x = 2; - - while (x--) { - if (parallax[x]) { - lagPointer[x] = pointer[x] + this.decay * (this.pointer[x] - pointer[x]); - } - } - this.pointer = lagPointer; - } - }; - } - function Port(object, options) { var self = this, elem = object instanceof $ ? object : $(object) , From 36e4c1073117b89b4701176044c14736a95283c8 Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Thu, 12 Apr 2012 22:07:07 +0200 Subject: [PATCH 8/9] Corrected landscape mode --- js/jquery.jparallax.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/js/jquery.jparallax.js b/js/jquery.jparallax.js index db3f6a2..b0a9d44 100644 --- a/js/jquery.jparallax.js +++ b/js/jquery.jparallax.js @@ -477,22 +477,31 @@ }); } else { var self = this; + var orientation = (Math.abs(window.orientation) == 0) ? true : false; + + window.addEventListener('orientationchange', function() { + if (Math.abs(window.orientation) == 0) { + orientation = true; + } else { + orientation = false; + } + }, false); window.addEventListener('devicemotion', function (e) { var acceleration = e.accelerationIncludingGravity; - var facingUp = -1; + var upSideDown = -1; if (acceleration.z > 0) { - facingUp = +1; + upSideDown = +1; } - var tiltLR = Math.round(((acceleration.x) / 9.81) * -90); - var tiltFB = Math.round(((acceleration.y + 9.81) / 9.81) * 90 * facingUp); + var lr = Math.round(((acceleration.x) / 9.81) * -90); + var tb = Math.round(((acceleration.y + 9.81) / 9.81) * 90 * upSideDown); layers.trigger('DeviceMotionEvent', { - accelerationIncludingGravity:{ - x:tiltLR / 100, - y:tiltFB / 100 + accelerationIncludingGravity: { + x: ((orientation) ? lr : tb + 90) / 100, + y: ((orientation) ? tb : lr + 90) / 100 } }); }, false); From c95c7b007122c4f50644adcf49721c0792dfd260 Mon Sep 17 00:00:00 2001 From: Kersten Burkhardt Date: Thu, 12 Apr 2012 22:35:26 +0200 Subject: [PATCH 9/9] Switched to max version in demos --- demos/index.html | 5 +++-- demos/remotecontrol.html | 3 ++- demos/stalkbuttons.html | 3 ++- demos/target.html | 5 +++-- demos/thumbnails.html | 2 +- js/jquery.jparallax.js | 6 +++--- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/demos/index.html b/demos/index.html index d0cbe44..f275583 100644 --- a/demos/index.html +++ b/demos/index.html @@ -64,8 +64,9 @@

    jParallax Demos next

    - - + + + + + + + - + + + +