Skip to content

Commit 1dbc01d

Browse files
committed
initial implementation
1 parent 5a4f9f5 commit 1dbc01d

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

parallax.js

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*!
2+
* parallax.js v0.1 (http://pixelcog.github.io/parallax.js/)
3+
* Copyright (c) 2014 PixelCog, Inc.
4+
* Licensed under MIT (https://github.com/pixelcog/parallax.js/blob/master/LICENSE)
5+
*/
6+
7+
;(function ( $, window, document, undefined ) {
8+
9+
// Parallax Constructor Definition
10+
11+
var $body = $('body');
12+
13+
function Parallax(element, options) {
14+
this.$element = $(element).is('body') ? $(window) : $(element);
15+
this.scrollTop = this.$element.scrollTop();
16+
this.scrollWin = this.$element.height();
17+
this.options = $.extend({}, Parallax.defaults, options);
18+
this.selector = this.options.parallaxTarget || this.options.target || '';
19+
this.sliders = [];
20+
this.busy = false;
21+
this.fresh = false;
22+
23+
var self = this;
24+
25+
$(document).ready(function(){
26+
self.$element.on('scroll.px.parallax', function(){
27+
self.scrollTop = self.$element.scrollTop();
28+
self.requestRender();
29+
});
30+
31+
$(window).on('resize.px.parallax', function(){
32+
self.scrollWin = self.$element.height();
33+
self.fresh = false;
34+
self.requestRender();
35+
});
36+
37+
self.reload();
38+
});
39+
};
40+
41+
Parallax.defaults = {
42+
'target': null,
43+
'speed': 0.2
44+
}
45+
46+
Parallax.prototype.reload = function() {
47+
var self = this;
48+
49+
$body
50+
.find(this.selector)
51+
.filter(':visible')
52+
.each(function() {
53+
var slider = {};
54+
55+
slider.$holder = $(this);
56+
slider.$image = slider.$holder.find('img').first();
57+
slider.speed = self.options.speed;
58+
59+
var data = slider.$image.data();
60+
61+
slider.$image.one('load', function() {
62+
if (data.naturalWidth && data.naturalHeight) {
63+
slider.imageRatio = data.naturalWidth / data.naturalHeight;
64+
} else {
65+
if (this.naturalWidth == undefined || this.naturalHeight == undefined) {
66+
var tmp = new Image();
67+
tmp.src = this.src;
68+
this.naturalWidth = tmp.width;
69+
this.naturalHeight = tmp.height;
70+
}
71+
slider.imageRatio = this.naturalWidth / this.naturalHeight;
72+
}
73+
74+
self.sliders.push(slider);
75+
self.fresh = false;
76+
self.requestRender();
77+
});
78+
79+
if (data.naturalWidth && data.naturalHeight || slider.image[0].complete) {
80+
slider.$image.trigger('load');
81+
}
82+
});
83+
};
84+
85+
Parallax.prototype.refresh = function() {
86+
console.log('refreshing');
87+
var screenHeight = $(window).height();
88+
var i, slider, holderWidth, holderHeight, imageHeightMin;
89+
90+
for (i = 0; i < this.sliders.length; ++i) {
91+
slider = this.sliders[i];
92+
slider.holderWidth = slider.$holder.width();
93+
slider.holderHeight = slider.$holder.height();
94+
slider.holderOffset = slider.$holder.offset().top;
95+
slider.holderBottom = slider.holderOffset + slider.holderHeight;
96+
imageHeightMin = Math.round(
97+
screenHeight - (screenHeight - slider.holderHeight) * slider.speed
98+
);
99+
100+
if (imageHeightMin * slider.imageRatio >= slider.holderWidth) {
101+
slider.imageWidth = Math.round(imageHeightMin * slider.imageRatio);
102+
slider.imageHeight = imageHeightMin;
103+
slider.offsetX = Math.round((slider.holderWidth - slider.imageWidth) / 2);
104+
slider.offsetBaseY = 0;
105+
} else {
106+
slider.imageWidth = slider.holderWidth;
107+
slider.imageHeight = Math.round(slider.holderWidth / slider.imageRatio);
108+
slider.offsetX = 0;
109+
slider.offsetBaseY = Math.round((imageHeightMin - slider.imageHeight) / 2);
110+
}
111+
}
112+
113+
for (i = 0; i < this.sliders.length; ++i) {
114+
/*
115+
this.sliders[i].$holder.css({
116+
position: 'relative'
117+
});
118+
this.sliders[i].$image.css({
119+
position: 'absolute',
120+
width: slider.imageWidth,
121+
height: slider.imageHeight,
122+
left: slider.offsetX,
123+
top: slider.offsetBaseY
124+
});
125+
*/
126+
this.sliders[i].$image[0].style.cssText =
127+
'-webkit-transform: translate3d(' + slider.offsetX + 'px, ' + slider.offsetBaseY + 'px, 0px);' +
128+
'width:' + slider.imageWidth + 'px;' +
129+
'height:' + slider.imageHeight + 'px;'
130+
;
131+
}
132+
133+
this.fresh = true;
134+
};
135+
136+
Parallax.prototype.render = function() {
137+
this.fresh || this.refresh();
138+
139+
var screenTop = this.scrollTop;
140+
var screenBottom = this.scrollTop + this.scrollWin;
141+
var i, slider, base;
142+
143+
for (i = 0; i < this.sliders.length; ++i) {
144+
slider = this.sliders[i];
145+
/*
146+
slider.$image.css('top', slider.offsetY);
147+
*/
148+
if (slider.holderBottom > screenTop && slider.holderOffset < screenBottom) {
149+
base = this.scrollTop - slider.holderOffset;
150+
slider.offsetY = Math.round(base - base * slider.speed) + slider.offsetBaseY;
151+
slider.$image[0].style.cssText =
152+
'-webkit-transform: translate3d(' + slider.offsetX + 'px, ' + slider.offsetY + 'px, 0px);' +
153+
'width:' + slider.imageWidth + 'px;' +
154+
'height:' + slider.imageHeight + 'px;'
155+
;
156+
}
157+
}
158+
};
159+
160+
Parallax.prototype.requestRender = function() {
161+
var self = this;
162+
163+
if (!this.busy) {
164+
this.busy = true;
165+
window.requestAnimationFrame(function() {
166+
self.render();
167+
self.busy = false;
168+
});
169+
}
170+
};
171+
172+
173+
// Parallax Plugin Definition
174+
175+
function Plugin(option) {
176+
return this.each(function () {
177+
var $this = $(this);
178+
var data = $this.data('px.parallax');
179+
var options = typeof option == 'object' && option;
180+
181+
if (!data) $this.data('px.parallax', (data = new Parallax(this, options)));
182+
if (typeof option == 'string') data[option]();
183+
})
184+
};
185+
186+
var old = $.fn.parallax;
187+
188+
$.fn.parallax = Plugin;
189+
$.fn.parallax.Constructor = Parallax;
190+
191+
192+
// Parallax No Conflict
193+
194+
$.fn.parallax.noConflict = function () {
195+
$.fn.parallax = old;
196+
return this;
197+
};
198+
199+
200+
// Parallax Data-API
201+
202+
$(window).on('load.px.parallax.data-api', function () {
203+
$('[data-parallax="scroll"]').each(function () {
204+
var $elm = $(this);
205+
Plugin.call($elm, $elm.data());
206+
});
207+
});
208+
209+
210+
// Polyfill for requestAnimationFrame
211+
// via: https://gist.github.com/paulirish/1579671
212+
213+
(function() {
214+
var lastTime = 0;
215+
var vendors = ['ms', 'moz', 'webkit', 'o'];
216+
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
217+
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
218+
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
219+
|| window[vendors[x]+'CancelRequestAnimationFrame'];
220+
}
221+
222+
if (!window.requestAnimationFrame)
223+
window.requestAnimationFrame = function(callback, element) {
224+
var currTime = new Date().getTime();
225+
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
226+
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
227+
timeToCall);
228+
lastTime = currTime + timeToCall;
229+
return id;
230+
};
231+
232+
if (!window.cancelAnimationFrame)
233+
window.cancelAnimationFrame = function(id) {
234+
clearTimeout(id);
235+
};
236+
}());
237+
238+
}(jQuery, window, document));

parallax.min.js

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)