-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcard.js
151 lines (126 loc) · 5.26 KB
/
card.js
1
2
3
4
5
6
7
8
9
10
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// utility functions
if(!Util) function Util () {};
Util.osHasReducedMotion = function() {
if(!window.matchMedia) return false;
var matchMediaObj = window.matchMedia('(prefers-reduced-motion: reduce)');
if(matchMediaObj) return matchMediaObj.matches;
return false;
};
// File#: _1_stacking-cards
// Usage: codyhouse.co/license
(function() {
var StackCards = function(element) {
this.element = element;
this.items = this.element.getElementsByClassName('js-stack-cards__item');
this.scrollingFn = false;
this.scrolling = false;
initStackCardsEffect(this);
initStackCardsResize(this);
};
function initStackCardsEffect(element) { // use Intersection Observer to trigger animation
setStackCards(element); // store cards CSS properties
var observer = new IntersectionObserver(stackCardsCallback.bind(element), { threshold: [0, 1] });
observer.observe(element.element);
};
function initStackCardsResize(element) { // detect resize to reset gallery
element.element.addEventListener('resize-stack-cards', function(){
setStackCards(element);
animateStackCards.bind(element);
});
};
function stackCardsCallback(entries) { // Intersection Observer callback
if(entries[0].isIntersecting) {
if(this.scrollingFn) return; // listener for scroll event already added
stackCardsInitEvent(this);
} else {
if(!this.scrollingFn) return; // listener for scroll event already removed
window.removeEventListener('scroll', this.scrollingFn);
this.scrollingFn = false;
}
};
function stackCardsInitEvent(element) {
element.scrollingFn = stackCardsScrolling.bind(element);
window.addEventListener('scroll', element.scrollingFn);
};
function stackCardsScrolling() {
if(this.scrolling) return;
this.scrolling = true;
window.requestAnimationFrame(animateStackCards.bind(this));
};
function setStackCards(element) {
// store wrapper properties
element.marginY = getComputedStyle(element.element).getPropertyValue('--stack-cards-gap');
getIntegerFromProperty(element); // convert element.marginY to integer (px value)
element.elementHeight = element.element.offsetHeight;
// store card properties
var cardStyle = getComputedStyle(element.items[0]);
element.cardTop = Math.floor(parseFloat(cardStyle.getPropertyValue('top')));
element.cardHeight = Math.floor(parseFloat(cardStyle.getPropertyValue('height')));
// store window property
element.windowHeight = window.innerHeight;
// reset margin + translate values
if(isNaN(element.marginY)) {
element.element.style.paddingBottom = '0px';
} else {
element.element.style.paddingBottom = (element.marginY*(element.items.length - 1))+'px';
}
for(var i = 0; i < element.items.length; i++) {
if(isNaN(element.marginY)) {
element.items[i].style.transform = 'none;';
} else {
element.items[i].style.transform = 'translateY('+element.marginY*i+'px)';
}
}
};
function getIntegerFromProperty(element) {
var node = document.createElement('div');
node.setAttribute('style', 'opacity:0; visbility: hidden;position: absolute; height:'+element.marginY);
element.element.appendChild(node);
element.marginY = parseInt(getComputedStyle(node).getPropertyValue('height'));
element.element.removeChild(node);
};
function animateStackCards() {
if(isNaN(this.marginY)) { // --stack-cards-gap not defined - do not trigger the effect
this.scrolling = false;
return;
}
var top = this.element.getBoundingClientRect().top;
if( this.cardTop - top + this.element.windowHeight - this.elementHeight - this.cardHeight + this.marginY + this.marginY*this.items.length > 0) {
this.scrolling = false;
return;
}
for(var i = 0; i < this.items.length; i++) { // use only scale
var scrolling = this.cardTop - top - i*(this.cardHeight+this.marginY);
if(scrolling > 0) {
var scaling = i == this.items.length - 1 ? 1 : (this.cardHeight - scrolling*0.05)/this.cardHeight;
this.items[i].style.transform = 'translateY('+this.marginY*i+'px) scale('+scaling+')';
} else {
this.items[i].style.transform = 'translateY('+this.marginY*i+'px)';
}
}
this.scrolling = false;
};
// initialize StackCards object
var stackCards = document.getElementsByClassName('js-stack-cards'),
intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
reducedMotion = Util.osHasReducedMotion();
if(stackCards.length > 0 && intersectionObserverSupported && !reducedMotion) {
var stackCardsArray = [];
for(var i = 0; i < stackCards.length; i++) {
(function(i){
stackCardsArray.push(new StackCards(stackCards[i]));
})(i);
}
var resizingId = false,
customEvent = new CustomEvent('resize-stack-cards');
window.addEventListener('resize', function() {
clearTimeout(resizingId);
resizingId = setTimeout(doneResizing, 500);
});
function doneResizing() {
for( var i = 0; i < stackCardsArray.length; i++) {
(function(i){stackCardsArray[i].element.dispatchEvent(customEvent)})(i);
};
};
}
}());