├── img
└── bg
│ └── stationblue.jpg
├── README.md
├── css
└── style.css
├── LICENSE
├── index.html
└── js
├── ahrelax.min.js
└── ahrelax.js
/img/bg/stationblue.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conorluddy/ahRelax/HEAD/img/bg/stationblue.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ahrelax
2 | =======
3 |
4 | Experimental lightweight JS/jQuery script to facilitate quick scroll based animations. Way out of date - wouldn't recommend using for anything!
5 |
6 | Currently less than 1kb minified, but will probably need to grow to be useful.
7 |
8 | Tried to make use of some of the tips in here, without making it as complicated:
9 | https://medium.com/@dhg/parallax-done-right-82ced812e61c
10 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 |
2 | html, body, div, span, applet, object, iframe,
3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4 | a, abbr, acronym, address, big, cite, code,
5 | del, dfn, em, img, ins, kbd, q, s, samp,
6 | small, strike, strong, sub, sup, tt, var,
7 | b, u, i, center,
8 | dl, dt, dd, ol, ul, li,
9 | fieldset, form, label, legend,
10 | table, caption, tbody, tfoot, thead, tr, th, td,
11 | article, aside, canvas, details, embed,
12 | figure, figcaption, footer, header, hgroup,
13 | menu, nav, output, ruby, section, summary,
14 | time, mark, audio, video {
15 | margin: 0;
16 | padding: 0;
17 | border: 0;
18 | font: inherit;
19 | font-size: 100%;
20 | vertical-align: baseline;
21 | }
22 |
23 | html, body{
24 | height: 100%;
25 | }
26 |
27 | .row {
28 | width: 100%;
29 | height: 66%;
30 | position: relative;
31 | display: block;
32 | }
33 |
34 | #move-me{
35 | background: url("../img/bg/stationblue.jpg") no-repeat scroll 0 0 transparent;
36 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Conor
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.
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | AhRelax - Parallax facilitator
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/js/ahrelax.min.js:
--------------------------------------------------------------------------------
1 | define(["jquery"],function(e){var b=0,g=0,i=0,c=0,h=((g-b)/2)+b,f=0,a=e(window),d=e("body"),k=[{wrap:"#piece-station",target:null,rate:-0.3,tweak:0,effect:"bgSlideVertical"}],j={bgSlideVertical:function(m,n){var l=(n*m.rate).toFixed(2);
2 | l-=m.rate<0?m.height-m.tweak:0;e(m.wrap).css("background-position","0 "+l+"px");},elementSlideVertical:function(m,n){var l=(n*m.rate).toFixed(2);l-=m.rate<0?m.height-m.tweak:0;
3 | e(m.wrap).css("transform","translate3d(0,"+l+"px,0");}};setup=function(){var m;i=a.height();c=a.width();b=a.scrollTop();g=a.scrollTop()+i;for(var l=k.length-1;
4 | l>=0;l--){m=e(k[l].wrap);k[l].starts=m.offset().top;k[l].ends=m.offset().top+m.height();k[l].height=m.height();k[l].lasts=m.height()/i;}};posUpdate=function(){window.requestAnimationFrame(function(){setVpTop();
5 | animatePieces();});};setVpTop=function(){b=a.scrollTop();g=a.scrollTop()+i;};calcVisibilty=function(o){var n=e(o.wrap),s=o.starts,l=o.ends,p=sb;if(p){n.addClass("inView");
6 | }else{n.removeClass("inView");return p;}var m=((g-b)/2)+b,q=((l-s)/2)+s,r=1-((m-q)/i*-1)<1?(1-((m-q)/i*-1)).toFixed(2):1;progressOut=1-((m-q)/i*-1)>1?(((m-q)/i*-1)*-1).toFixed(2):0;
7 | o.progressIn=r;o.progressOut=progressOut;o.midpoint=q;if(r>0.5){n.addClass("mostInView");n.addClass("beenInView");}else{n.removeClass("mostInView");}return p;
8 | };animatePieces=function(){for(var m=k.length-1;m>=0;m--){var n=e(k[m].wrap),p=false,q=k[m].starts,l=k[m].ends,o;p=calcVisibilty(k[m]);if(p){o=q-g;switch(k[m].effect){case"bgSlideVertical":j.bgSlideVertical(k[m],o);
9 | break;case"opacity":j.opacity(k[m]);break;}}}};init=function(){setup();a.resize(setup);f=setInterval(posUpdate,10);};});
--------------------------------------------------------------------------------
/js/ahrelax.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Each & Other website, 2015 [www.eachandother.com]
3 | * Author: Conor Luddy
4 | *
5 | *
6 | * ---------
7 | *
8 | *
9 | * Attach this to a front end module by giving its root
10 | * element the attribute: data-js-module=""
11 | */
12 |
13 | (function(window, document, EachAnd, $, Modernizr, undefined) {
14 | 'use strict';
15 |
16 | EachAnd.util.ahhrelax = function() {
17 |
18 | var
19 | //Viewport
20 | vpTop = 0,
21 | vpBottom = 0,
22 | vpHeight = 0,
23 | vpWidth = 0,
24 | vpMidpoint = ((vpBottom - vpTop) / 2) + vpTop,
25 | //Setup fills this with individual objects we can animate
26 | initialisedPieces = [],
27 | //Other
28 | scrollInterval = 0,
29 | $window = $(window),
30 | $body = $('body');
31 |
32 | /*
33 | * These are the classes that get applied to each 'piece'
34 | */
35 | var viewClass = {
36 | //Applies to all pieces
37 | pieceToBeUsed: 'js-ar-piece',
38 | //Has never been in the viewport
39 | notYetBeenInView: 'js-ar-unSeen',
40 | //Has been in the viewport but may or may not still be
41 | hasBeenInView: 'js-ar-beenInView',
42 | //Is somewhere in view
43 | currentlyInView: 'js-ar-inView',
44 | //Is more than 50% of the way into the centre (based on midpoints - may need more accurate implementation)
45 | mostlyInView: 'js-ar-mostInView',
46 | //Is more than 50% of the way past the centre (based on midpoints - may need more accurate implementation)
47 | mostlyPastView: 'js-ar-mostlyPastView'
48 | };
49 |
50 | /*
51 | * Targeted pieces or elements
52 | * New effects can be defined for use here
53 | *
54 | * Pieces potentially get the following properties:
55 | * wrap
56 | * rate
57 | * tweak
58 | * effect
59 | * starts
60 | * ends
61 | * lasts
62 | * height
63 | * progressIn - 0-1, maxes out at 1 when the piece is actually taking up some vp space
64 | * progressOut
65 | * midpoint
66 | */
67 | var piece = [{
68 | wrap: '.m-statement',
69 | effect: 'fadeOutOnExit',
70 | rate: 2
71 | }];
72 |
73 | // , {
74 | // //Just apply the classes used for visibility and don't do any parallaxy stuff
75 | // // wrap: '.row-about',
76 | // // effect: 'fadeOutOnExit',
77 | // // rate: 2
78 | // }, {
79 | // //Just apply the classes used for visibility and don't do any parallaxy stuff
80 | // // wrap: '.row-clients'
81 | // }],
82 |
83 |
84 |
85 |
86 | /*
87 | * Effects for assigning to our animatable pieces
88 | *
89 | * Define whatever you can think of. There's plenty of data to use.
90 | */
91 | var effect = {
92 |
93 | bgSlideVertical: function(piece, relativeTop) {
94 | var newvalue = (relativeTop * piece.rate).toFixed(2);
95 | //If the rate is negative, background position should be
96 | //shifted up so that it can move down without leaving a gap.
97 | newvalue = piece.rate < 0 ? piece.height - piece.tweak : 0;
98 | $(piece.wrap).css('background-position', '0 ' + newvalue + 'px');
99 | },
100 |
101 | elementSlideVertical: function(piece, relativeTop) {
102 | // var newvalue = ( relativeTop * piece.rate ).toFixed( 2 );
103 | // newvalue -= piece.rate < 0 ? piece.height - piece.tweak : 0;
104 | // $( piece.wrap ).css( 'transform', 'translate3d(0,' + newvalue + 'px,0' );
105 | },
106 |
107 | fadeOutOnExit: function(piece) {
108 | var rate = typeof(piece.rate) === 'undefined' ? 1 : piece.rate;
109 | piece.element.css('opacity', (1 - piece.progressOut * rate).toFixed(2));
110 | },
111 |
112 | // fadeInOnApproach: function(piece) {
113 | // var rate = typeof(piece.rate) === 'undefined' ? 1 : piece.rate;
114 | // piece.element.css('opacity', (0 + piece.progressIn * rate).toFixed(2));
115 | // },
116 |
117 | debuggy: function(piece) {
118 | console.log(piece);
119 | }
120 |
121 | };
122 |
123 |
124 |
125 |
126 |
127 |
128 | /*
129 | * Calculate some dimensions
130 | */
131 | function setup() {
132 |
133 | var
134 | $pw,
135 | thisPiece = {};
136 |
137 | vpHeight = $window.height();
138 | vpWidth = $window.width();
139 | vpTop = $window.scrollTop();
140 | vpBottom = $window.scrollTop() + vpHeight;
141 |
142 | //Calculate the start and end points
143 | for (var i = piece.length - 1; i >= 0; i--) {
144 | //Piece could be a jQuery collection of elemeents, not jst one...
145 | $pw = $(piece[i].wrap);
146 |
147 | for (var j = 0; j < $pw.length; j++) {
148 |
149 | thisPiece = {};
150 |
151 | $.extend( thisPiece, piece[i] );
152 |
153 | thisPiece.element = $pw.eq(j);
154 | //Start of active section
155 | thisPiece.starts = $pw.eq(j).offset().top;
156 | //End of active section
157 | thisPiece.ends = thisPiece.starts + $pw.eq(j).height();
158 | //Save this so it doesn't need to calculate it every 10ms
159 | thisPiece.height = $pw.eq(j).height();
160 | //Ratio of section height to viewport height... has to be useful for something...
161 | thisPiece.lasts = $pw.eq(j).height() / vpHeight;
162 |
163 | initialisedPieces.push(thisPiece);
164 |
165 | thisPiece.element.addClass(viewClass.notYetBeenInView);
166 |
167 | }
168 | }
169 | }
170 |
171 |
172 |
173 |
174 |
175 | /*
176 | * Animate
177 | */
178 | function posUpdate() {
179 | window.requestAnimationFrame(function() {
180 | setVpTop();
181 | animatePieces();
182 | });
183 | }
184 |
185 |
186 |
187 | function setVpTop() {
188 | // Viewport top
189 | vpTop = $window.scrollTop();
190 | // Viewport bottom
191 | vpBottom = $window.scrollTop() + vpHeight;
192 | }
193 |
194 |
195 |
196 | function manageVisibilty(piece) {
197 |
198 | var
199 | $piece = piece.element,
200 | pieceTop = piece.starts,
201 | pieceBot = piece.ends,
202 | vpMidpoint,
203 | pieceMidpoint,
204 | progressIn,
205 | progressOut,
206 | inview = pieceTop < vpBottom && pieceBot > vpTop;
207 |
208 | if (inview) {
209 | $piece.addClass(viewClass.currentlyInView);
210 | $piece.addClass(viewClass.hasBeenInView);
211 | //
212 | $piece.removeClass(viewClass.notYetBeenInView);
213 | } else {
214 | $piece.removeClass(viewClass.currentlyInView);
215 | return inview;
216 | }
217 |
218 | //Midpoint of viewport in relation to page
219 | vpMidpoint = ((vpBottom - vpTop) / 2) + vpTop;
220 |
221 | //Midpoint of targeted piece in relation to page
222 | pieceMidpoint = piece.midpoint = ((pieceBot - pieceTop) / 2) + pieceTop;
223 |
224 | //0% when it just comes into vp, 100% when midpoints match
225 | progressIn = piece.progressIn = 1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1) < 1 ? (1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1)).toFixed(2) : 1;
226 |
227 | //0% when when midpoints match, 100% when it exits vp
228 | progressOut = piece.progressOut = 1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1) > 1 ? (((vpMidpoint - pieceMidpoint) / vpHeight * -1) * -1).toFixed(2) : 0;
229 |
230 | //Add, change and remove these as you see fit:
231 |
232 | //As piece is scrolled towards centre
233 | if (progressIn > 0.5) $piece.addClass(viewClass.mostlyInView);
234 | else $piece.removeClass(viewClass.mostlyInView);
235 |
236 | //As piece is scrolled beyond centre
237 | if (progressOut > 0.5) $piece.addClass(viewClass.mostlyPastView);
238 | else $piece.removeClass(viewClass.mostlyPastView);
239 |
240 | return inview;
241 | }
242 |
243 |
244 |
245 |
246 |
247 | /**
248 | * animatePieces
249 | */
250 | function animatePieces() {
251 |
252 | for (var i = initialisedPieces.length - 1; i >= 0; i--) {
253 |
254 | var
255 | inview = false,
256 | pieceTop = initialisedPieces[i].starts,
257 | pieceBot = initialisedPieces[i].ends,
258 | relativeTop;
259 |
260 | inview = manageVisibilty( initialisedPieces[i] );
261 |
262 | // element is in view if it's top is less than vp bottom, and its bottom is greater than vp top
263 | if ( inview ) {
264 | relativeTop = pieceTop - vpBottom;
265 |
266 | if( typeof( initialisedPieces[i].effect ) !== 'undefined' ) {
267 | switch ( initialisedPieces[i].effect ){
268 |
269 | case 'bgSlideVertical':
270 | effect.bgSlideVertical( initialisedPieces[i], relativeTop );
271 | break;
272 |
273 | case 'elementSlideVertical':
274 | effect.elementSlideVertical( initialisedPieces[i], relativeTop );
275 | break;
276 |
277 | case 'fadeOutOnExit':
278 | effect.fadeOutOnExit( initialisedPieces[i] );
279 | break;
280 |
281 | //Easy way to explore data we can play with.
282 | //You can set inverval to 30sec or something
283 | //down below if you want time to read the output.
284 | case 'debuggy':
285 | effect.debuggy( initialisedPieces[i] );
286 | break;
287 | }
288 |
289 | }
290 |
291 | }
292 |
293 | }
294 |
295 | }
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 | /*
306 | * Initialise page
307 | */
308 | function init() {
309 | //Save necessary widths, heights, and other important factors
310 | setup();
311 |
312 | //Update them on window resize
313 | $window.resize(setup);
314 |
315 | //Update the page every x
316 | scrollInterval = setInterval(posUpdate, 50);
317 | }
318 |
319 |
320 | return init();
321 | };
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 | //Move elsewhere
330 | EachAnd.util.ahhrelax();
331 |
332 |
333 |
334 |
335 |
336 |
337 | })(this.window, this.document, this.EachAnd, jQuery, Modernizr);
338 |
--------------------------------------------------------------------------------