├── README.md
├── LICENSE.md
├── parallax.min.js
└── parallax.js
/README.md:
--------------------------------------------------------------------------------
1 | # Parallax
2 |
3 | Simple 0.8KB plugin for [Animate Plus](https://github.com/bendc/animateplus) that lets you easily
4 | create layered icons. [View demo](http://animateplus.com/demos/parallax/).
5 |
6 | ## Usage
7 |
8 | 1. Include `animate.min.js`
9 | ([download](https://github.com/bendc/animateplus/blob/master/animate.min.js)) and `parallax.min.js`
10 | in your document.
11 | 2. Define a container with a `parallax` class and add your image layers in it.
12 |
13 | ```html
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ```
23 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Benjamin De Cock
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/parallax.min.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("DOMContentLoaded",function(){function k(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b {
2 | "use strict";
3 |
4 | const icons = Object.freeze([...document.getElementsByClassName("parallax")]);
5 | const threshold = .2;
6 | const perspective = 800;
7 |
8 | const isLast = (arr, el) => [...arr].pop() === el;
9 |
10 | const centerLayers = (icon, layers) => {
11 | const sizes = layers.map(layer => {
12 | const rect = layer.getBoundingClientRect();
13 | return Object.freeze({
14 | width: rect.width,
15 | height: rect.height
16 | });
17 | });
18 |
19 | layers.forEach((layer, index) => {
20 | const size = sizes[index];
21 | layer.style.position = "absolute";
22 | layer.style.top = `calc(50% - ${size.height / 2}px)`;
23 | layer.style.left = `calc(50% - ${size.width / 2}px)`;
24 | });
25 |
26 | icon.style.overflow = "hidden";
27 | if (getComputedStyle(icon).getPropertyValue("position") != "static") return;
28 | icon.style.position = "relative";
29 | };
30 |
31 | const getParallax = (event, coordinates, level) => {
32 | const cursor = Object.freeze({
33 | x: (event.clientX - coordinates.left) - (coordinates.width / 2),
34 | y: (event.clientY - coordinates.top) - (coordinates.height / 2)
35 | });
36 |
37 | const limit = 1 - level * threshold;
38 |
39 | return Object.freeze({
40 | x: cursor.x * (1 - Math.abs(cursor.x) / coordinates.width) * threshold * limit,
41 | y: cursor.y * (1 - Math.abs(cursor.y) / coordinates.height) * threshold * limit
42 | });
43 | };
44 |
45 | const setParallax = icon => {
46 | const coordinates = icon.getBoundingClientRect();
47 | const layers = Object.freeze([...icon.getElementsByTagName("img")]);
48 |
49 | const hover = event =>
50 | layers.forEach((layer, level) => {
51 | const {x, y} = getParallax(event, coordinates, level);
52 | layer.style.transform = `translate(${x}px, ${y}px)`;
53 | if (!isLast(layers, layer)) return;
54 | icon.style.transform = `perspective(${perspective}px) rotateX(${y}deg) rotateY(${-x}deg)`;
55 | });
56 |
57 | const events = Object.freeze({
58 | enter: event => {
59 | const easing = "easeOutQuad";
60 | const duration = 150;
61 | animate.stop([icon, ...layers]);
62 | layers.forEach((layer, level) => {
63 | const {x, y} = getParallax(event, coordinates, level);
64 | animate({
65 | el: layer,
66 | translateX: x,
67 | translateY: y,
68 | easing,
69 | duration
70 | });
71 | if (!isLast(layers, layer)) return;
72 | animate({
73 | el: icon,
74 | perspective: [perspective, perspective],
75 | rotateX: y,
76 | rotateY: -x,
77 | easing,
78 | duration,
79 | complete: () => icon.addEventListener("mousemove", hover)
80 | });
81 | });
82 | },
83 | leave: event =>
84 | layers.forEach((layer, level) => {
85 | const {x, y} = getParallax(event, coordinates, level);
86 | animate({
87 | el: layer,
88 | translateX: [x, 0],
89 | translateY: [y, 0]
90 | });
91 | if (!isLast(layers, layer)) return;
92 | animate({
93 | el: icon,
94 | perspective: [perspective, perspective],
95 | rotateX: [y, 0],
96 | rotateY: [-x, 0],
97 | complete: () => icon.removeEventListener("mousemove", hover)
98 | });
99 | })
100 | });
101 |
102 | centerLayers(icon, layers);
103 | Object.keys(events).forEach(event => icon.addEventListener(`mouse${event}`, events[event]));
104 | };
105 |
106 | icons.forEach(setParallax);
107 | });
108 |
--------------------------------------------------------------------------------