Parallax

指示智能设备的方位的视差引擎

Parallax.js

Parallax Engine that reacts to the orientation of a smart device. Where no gyroscope or motion detection hardware is available, the position of the cursor is used instead.

Check out this demo to see it in action!

Setup

Create a list of elements giving each item that you want to move within your parallax scene a class of layer and a data-depth attribute specifying its depth within the scene. A depth of 0 will cause the layer to remain stationary, and a depth of 1 will cause the layer to move by the total effect of the calculated motion. Values inbetween 0 and 1 will cause the layer to move by an amount relative to the supplied ratio.

<ul id="scene">
  <li class="layer" data-depth="0.00"><img src="layer1.png"></li>
  <li class="layer" data-depth="0.20"><img src="layer2.png"></li>
  <li class="layer" data-depth="0.40"><img src="layer3.png"></li>
  <li class="layer" data-depth="0.60"><img src="layer4.png"></li>
  <li class="layer" data-depth="0.80"><img src="layer5.png"></li>
  <li class="layer" data-depth="1.00"><img src="layer6.png"></li>
</ul>

To kickoff a Parallax scene, select your parent DOM Element and pass it to the Parallax constructor.

var scene = document.getElementById('scene');
var parallax = new Parallax(scene);

Understanding Layer Motion Calculations

The amount of motion that each layer moves by depends on 3 contributing factors:

  1. The scalarX and scalarY values (see Behaviours below for configuration)
  2. The dimensions of the parent DOM element
  3. The depth of a layer within a parallax scene (specified by it's data-depth attribute)

The calculation for this motion is as follows:

xMotion = parentElement.width  * (scalarX / 100) * layerDepth
yMotion = parentElement.height * (scalarY / 100) * layerDepth

So for a layer with a data-depth value of 0.5 within a scene that has both the scalarX and scalarY values set to 10 ( the default ) where the containing scene element is 1000px x 1000px, the total motion of the layer in both x and y would be:

xMotion = 1000 * (10 / 100) * 0.5 = 50 # 50px of positive and negative motion in x
yMotion = 1000 * (10 / 100) * 0.5 = 50 # 50px of positive and negative motion in y

Behaviours

There are a number of behaviours that you can setup for any given Parallax instance. These behaviours can either be specified in the markup via data attributes or in JavaScript via the constructor and API.

Behaviour Values Description
relativeInput true or false Specifies whether or not to use the coordinate system of the element passed to the parallax constructor. Mouse input only.
clipRelativeInput true or false Specifies whether or not to clip the mouse input to the bounds of the element passed to the parallax constructor. Mouse input only.
calibrate-x true or false Specifies whether or not to cache & calculate the motion relative to the initial x axis value on initialisation.
calibrate-y true or false Specifies whether or not to cache & calculate the motion relative to the initial y axis value on initialisation.
invert-x true or false true moves layers in opposition to the device motion, false slides them away.
invert-y true or false true moves layers in opposition to the device motion, false slides them away.
limit-x number or false A numeric value limits the total range of motion in x, false allows layers to move with complete freedom.
limit-y number or false A numeric value limits the total range of motion in y, false allows layers to move with complete freedom.
scalar-x number Multiplies the input motion by this value, increasing or decreasing the sensitivity of the layer motion.
scalar-y number Multiplies the input motion by this value, increasing or decreasing the sensitivity of the layer motion.
friction-x number 0 - 1 The amount of friction the layers experience. This essentially adds some easing to the layer motion.
friction-y number 0 - 1 The amount of friction the layers experience. This essentially adds some easing to the layer motion.
origin-x number The x origin of the mouse input. Defaults to 0.5 (the center). 0 moves the origin to the left edge, 1 to the right edge. Mouse input only.
origin-y number The y origin of the mouse input. Defaults to 0.5 (the center). 0 moves the origin to the top edge, 1 to the bottom edge. Mouse input only.

In addition to the behaviours described above, there are two methods enable() and disable() that activate and deactivate the Parallax instance respectively.

Behaviours: Data Attributes Example

<ul id="scene"
  data-calibrate-x="false"
  data-calibrate-y="true"
  data-invert-x="false"
  data-invert-y="true"
  data-limit-x="false"
  data-limit-y="10"
  data-scalar-x="2"
  data-scalar-y="8"
  data-friction-x="0.2"
  data-friction-y="0.8"
  data-origin-x="0.0"
  data-origin-y="1.0">
  <li class="layer" data-depth="0.00"><img src="graphics/layer1.png"></li>
  <li class="layer" data-depth="0.20"><img src="graphics/layer2.png"></li>
  <li class="layer" data-depth="0.40"><img src="graphics/layer3.png"></li>
  <li class="layer" data-depth="0.60"><img src="graphics/layer4.png"></li>
  <li class="layer" data-depth="0.80"><img src="graphics/layer5.png"></li>
  <li class="layer" data-depth="1.00"><img src="graphics/layer6.png"></li>
</ul>

Behaviours: Constructor Object Example

var scene = document.getElementById('scene');
var parallax = new Parallax(scene, {
  calibrateX: false,
  calibrateY: true,
  invertX: false,
  invertY: true,
  limitX: false,
  limitY: 10,
  scalarX: 2,
  scalarY: 8,
  frictionX: 0.2,
  frictionY: 0.8,
  originX: 0.0,
  originY: 1.0
});

Behaviours: API Example

var scene = document.getElementById('scene');
var parallax = new Parallax(scene);
parallax.enable();
parallax.disable();
parallax.updateLayers(); // Useful for reparsing the layers in your scene if you change their data-depth value
parallax.calibrate(false, true);
parallax.invert(false, true);
parallax.limit(false, 10);
parallax.scalar(2, 8);
parallax.friction(0.2, 0.8);
parallax.origin(0.0, 1.0);

jQuery

If you're using jQuery or Zepto and would prefer to use Parallax.js as a plugin, you're in luck!

$('#scene').parallax();

jQuery: Passing Options

$('#scene').parallax({
  calibrateX: false,
  calibrateY: true,
  invertX: false,
  invertY: true,
  limitX: false,
  limitY: 10,
  scalarX: 2,
  scalarY: 8,
  frictionX: 0.2,
  frictionY: 0.8,
  originX: 0.0,
  originY: 1.0
});

jQuery: API

var $scene = $('#scene').parallax();
$scene.parallax('enable');
$scene.parallax('disable');
$scene.parallax('updateLayers');
$scene.parallax('calibrate', false, true);
$scene.parallax('invert', false, true);
$scene.parallax('limit', false, 10);
$scene.parallax('scalar', 2, 8);
$scene.parallax('friction', 0.2, 0.8);
$scene.parallax('origin', 0.0, 1.0);

iOS

If you are writing a native iOS application and would like to use parallax.js within a UIWebView, you will need to do a little bit of work to get it running.

UIWebView no longer automatically receives the deviceorientation event, so your native application must intercept the events from the gyroscope and reroute them to the UIWebView:

  1. Include the CoreMotion framework #import <CoreMotion/CoreMotion.h> and create a reference to the UIWebView @property(nonatomic, strong) IBOutlet UIWebView *parallaxWebView;
  2. Add a property to the app delegate (or controller that will own the UIWebView) @property(nonatomic, strong) CMMotionManager *motionManager;
  3. Finally, make the following calls:
self.motionManager = [[CMMotionManager alloc] init];
if (self.motionManager.isGyroAvailable && !self.motionManager.isGyroActive) {
  [self.motionManager setGyroUpdateInterval:0.5f]; // Set the event update frequency (in seconds)
  [self.motionManager startGyroUpdatesToQueue:NSOperationQueue.mainQueue
                                  withHandler:^(CMGyroData *gyroData, NSError *error) {
    NSString *js = [NSString stringWithFormat:@"parallax.onDeviceOrientation({beta:%f, gamma:%f})", gyroData.rotationRate.x, gyroData.rotationRate.y];
    [self.parallaxWebView stringByEvaluatingJavaScriptFromString:js];
  }];
}

Build

As a prerequisite, you will need gulp installed: npm install -g gulp

npm install
gulp

During development you can have gulp watch the source directory for changes and automatically build the deploy files by running:

gulp watch

Author

Matthew Wagerfield: @wagerfield

License

Licensed under MIT. Enjoy.

Parallax.js

Parallax 是一个指示智能设备的方位的视差引擎,当没有陀螺仪或运动检测硬件可用时,可以用光标的位置来代替。

查看 demo 效果!

安装

创建一个元素列表,给每一个你想在视差场景中移动的元素加上一个 layer 样式和一个 data-depth 属性(指定该元素在场景中的层级深度)。深度为 0 将会导致该层保持静止,深度为 1 将会导致层通过计算运动的总效果移动,介于 01 的会导致层按照一定的比例移动。

<ul id="scene">
  <li class="layer" data-depth="0.00"><img src="layer1.png"></li>
  <li class="layer" data-depth="0.20"><img src="layer2.png"></li>
  <li class="layer" data-depth="0.40"><img src="layer3.png"></li>
  <li class="layer" data-depth="0.60"><img src="layer4.png"></li>
  <li class="layer" data-depth="0.80"><img src="layer5.png"></li>
  <li class="layer" data-depth="1.00"><img src="layer6.png"></li>
</ul>

为了启动 Parallax 场景,你需要选择你的父 DOM 元素,并且将其传给 Parallax 的构造函数。

var scene = document.getElementById('scene');
var parallax = new Parallax(scene);

理解层运动计算

每一个层的运动量取决于3个因素: 1. scalarXscalarY 值 (查看下面的 Behaviours ) 2. 父 DOM 元素的尺寸 3. 视差场景中一个层的 depth (由它的 data-depth 属性指定)

该运动的计算如下:

xMotion = parentElement.width  * (scalarX / 100) * layerDepth
yMotion = parentElement.height * (scalarY / 100) * layerDepth

所以一个层的 data-depth 值为 0.5scalarXscalarY 的值为 10默认值),父元素的尺寸为 1000px x 1000px ,那么这个层 xy 方向的整个运动应该是:

xMotion = 1000 * (10 / 100) * 0.5 = 50 # 50px of positive and negative motion in x
yMotion = 1000 * (10 / 100) * 0.5 = 50 # 50px of positive and negative motion in y

参数(Behaviours)

你可以给任意给定的 Parallax 实例设定一系列的参数。这些参数可以在 HTML 标签中通过 data- 属性指定或者在 JavaScript 中通过构造函数和 API 指定。

行为 描述
relativeInput true or false Specifies whether or not to use the coordinate system of the element passed to the parallax constructor. Mouse input only.
clipRelativeInput true or false Specifies whether or not to clip the mouse input to the bounds of the element passed to the parallax constructor. Mouse input only.
calibrate-x true or false Specifies whether or not to cache & calculate the motion relative to the initial x axis value on initialisation.
calibrate-y true or false Specifies whether or not to cache & calculate the motion relative to the initial y axis value on initialisation.
invert-x true or false true moves layers in opposition to the device motion, false slides them away.
invert-y true or false true moves layers in opposition to the device motion, false slides them away.
limit-x number or false A numeric value limits the total range of motion in x, false allows layers to move with complete freedom.
limit-y number or false A numeric value limits the total range of motion in y, false allows layers to move with complete freedom.
scalar-x number Multiplies the input motion by this value, increasing or decreasing the sensitivity of the layer motion.
scalar-y number Multiplies the input motion by this value, increasing or decreasing the sensitivity of the layer motion.
friction-x number 0 - 1 The amount of friction the layers experience. This essentially adds some easing to the layer motion.
friction-y number 0 - 1 The amount of friction the layers experience. This essentially adds some easing to the layer motion.
origin-x number The x origin of the mouse input. Defaults to 0.5 (the center). 0 moves the origin to the left edge, 1 to the right edge. Mouse input only.
origin-y number The y origin of the mouse input. Defaults to 0.5 (the center). 0 moves the origin to the top edge, 1 to the bottom edge. Mouse input only.

In addition to the behaviours described above, there are two methods enable() and disable() that activate and deactivate the Parallax instance respectively.

参数:通过Data 属性设置的例子

<ul id="scene"
  data-calibrate-x="false"
  data-calibrate-y="true"
  data-invert-x="false"
  data-invert-y="true"
  data-limit-x="false"
  data-limit-y="10"
  data-scalar-x="2"
  data-scalar-y="8"
  data-friction-x="0.2"
  data-friction-y="0.8"
  data-origin-x="0.0"
  data-origin-y="1.0">
  <li class="layer" data-depth="0.00"><img src="graphics/layer1.png"></li>
  <li class="layer" data-depth="0.20"><img src="graphics/layer2.png"></li>
  <li class="layer" data-depth="0.40"><img src="graphics/layer3.png"></li>
  <li class="layer" data-depth="0.60"><img src="graphics/layer4.png"></li>
  <li class="layer" data-depth="0.80"><img src="graphics/layer5.png"></li>
  <li class="layer" data-depth="1.00"><img src="graphics/layer6.png"></li>
</ul>

参数:通过构造函数设置的例子

var scene = document.getElementById('scene');
var parallax = new Parallax(scene, {
  calibrateX: false,
  calibrateY: true,
  invertX: false,
  invertY: true,
  limitX: false,
  limitY: 10,
  scalarX: 2,
  scalarY: 8,
  frictionX: 0.2,
  frictionY: 0.8,
  originX: 0.0,
  originY: 1.0
});

参数: 通过API 设置的例子

var scene = document.getElementById('scene');
var parallax = new Parallax(scene);
parallax.enable();
parallax.disable();
parallax.updateLayers(); // Useful for reparsing the layers in your scene if you change their data-depth value
parallax.calibrate(false, true);
parallax.invert(false, true);
parallax.limit(false, 10);
parallax.scalar(2, 8);
parallax.friction(0.2, 0.8);
parallax.origin(0.0, 1.0);

jQuery

如果你正在使用 jQuery 或者 Zepto 并且更喜欢将 Parallax.js 作为一个插件使用,那么你很幸运!

$('#scene').parallax();

jQuery: 传递参数

$('#scene').parallax({
  calibrateX: false,
  calibrateY: true,
  invertX: false,
  invertY: true,
  limitX: false,
  limitY: 10,
  scalarX: 2,
  scalarY: 8,
  frictionX: 0.2,
  frictionY: 0.8,
  originX: 0.0,
  originY: 1.0
});

jQuery: API

var $scene = $('#scene').parallax();
$scene.parallax('enable');
$scene.parallax('disable');
$scene.parallax('updateLayers');
$scene.parallax('calibrate', false, true);
$scene.parallax('invert', false, true);
$scene.parallax('limit', false, 10);
$scene.parallax('scalar', 2, 8);
$scene.parallax('friction', 0.2, 0.8);
$scene.parallax('origin', 0.0, 1.0);

iOS

如果你正在开发一个 iOS 本地应用 并且想在一个 UIWebView 中使用 parallax.js,你需要做一点事来让它运行起来。

UIWebView 不再自动接收 deviceorientation 事件,所以你的本地应用必须拦截这些陀螺仪的事件然后将它们重新路由给 UIWebView

  1. 引入 CoreMotion 框架 #import <CoreMotion/CoreMotion.h> 然后创建一个 UIWebView 的引用@property(nonatomic, strong) IBOutlet UIWebView *parallaxWebView;
  2. 给 app delegate(或者控制 UIWebView 的 controller)添加一个属性 @property(nonatomic, strong) CMMotionManager *motionManager;
  3. 最后,做下面的调用:
self.motionManager = [[CMMotionManager alloc] init];
if (self.motionManager.isGyroAvailable && !self.motionManager.isGyroActive) {
  [self.motionManager setGyroUpdateInterval:0.5f]; // Set the event update frequency (in seconds)
  [self.motionManager startGyroUpdatesToQueue:NSOperationQueue.mainQueue
                                  withHandler:^(CMGyroData *gyroData, NSError *error) {
    NSString *js = [NSString stringWithFormat:@"parallax.onDeviceOrientation({beta:%f, gamma:%f})", gyroData.rotationRate.x, gyroData.rotationRate.y];
    [self.parallaxWebView stringByEvaluatingJavaScriptFromString:js];
  }];
}

构建

作为一个前提条件,你需要安装 gulpnpm install -g gulp

npm install
gulp

在开发过程中,你可以让 gulp 监控 source 文件夹的变化,并且通过运行下面的命令来自动构建 deploy 的所有文件:

gulp watch

作者

Matthew Wagerfield: @wagerfield

许可

MIT. 下许可。

讨论区