Diff: STRATO-apps/wordpress_03/app/wp-content/themes/blocksy/static/js/frontend/parallax/rellax.js
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
// ------------------------------------------
2
+
// Rellax.js - v1.0.0
3
+
// Buttery smooth parallax library
4
+
// Copyright (c) 2016 Moe Amaya (@moeamaya)
5
+
// MIT license
6
+
//
7
+
// Thanks to Paraxify.js and Jaime Cabllero
8
+
// for parallax concepts
9
+
// ------------------------------------------
10
+
11
+
import { getCurrentScreen } from '../helpers/current-screen'
12
+
import innerHeight from './ios-inner-height'
13
+
14
+
// Ahh a pure function, gets new transform value
15
+
// based on scrollPostion and speed
16
+
// Allow for decimal pixel values
17
+
const updatePosition = (percentage, speed) => speed * (100 * (1 - percentage))
18
+
19
+
// We want to cache the parallax blocks'
20
+
// values: base, top, height, speed
21
+
// el: is dom object, return: el cache values
22
+
const createBlock = ({
23
+
el = null,
24
+
speed = null,
25
+
fitInsideContainer = null,
26
+
isVisible = false,
27
+
shouldSetHeightToIncrease = true,
28
+
parallaxBehavior = 'desktop:tablet:mobile',
29
+
}) => {
30
+
// Optional individual block speed as data attr, otherwise global speed
31
+
// Check if has percentage attr, and limit speed to 5, else limit it to 10
32
+
// The function is named clamp
33
+
speed = speed <= -5 ? -5 : speed >= 5 ? 5 : speed
34
+
35
+
// We need to guess the position the background will be, when the section
36
+
// will reach the top of the viewport. This calculation will be based on the
37
+
// speed for sure
38
+
if (fitInsideContainer && shouldSetHeightToIncrease) {
39
+
let heightWeWantToIncrease = 0
40
+
41
+
if (speed > 0) {
42
+
heightWeWantToIncrease = updatePosition(0.5, speed)
43
+
} else {
44
+
heightWeWantToIncrease =
45
+
updatePosition(
46
+
innerHeight() /
47
+
(fitInsideContainer.clientHeight + innerHeight()),
48
+
speed
49
+
) - updatePosition(0.5, speed)
50
+
}
51
+
52
+
heightWeWantToIncrease = Math.abs(heightWeWantToIncrease) * 2
53
+
54
+
if (!isVisible) {
55
+
el.parentNode.removeAttribute('style')
56
+
} else {
57
+
el.parentNode.style.height = `calc(100% + ${heightWeWantToIncrease}px)`
58
+
}
59
+
}
60
+
61
+
// initializing at scrollY = 0 (top of browser)
62
+
// ensures elements are positioned based on HTML layout.
63
+
64
+
let { top, height } = nullifyTransforms(
65
+
fitInsideContainer ? fitInsideContainer : el
66
+
)
67
+
68
+
var blockTop = pageYOffset + top
69
+
70
+
return {
71
+
parallaxBehavior,
72
+
shouldSetHeightToIncrease,
73
+
fitInsideContainer,
74
+
el,
75
+
top: blockTop,
76
+
height,
77
+
speed,
78
+
isVisible,
79
+
}
80
+
}
81
+
82
+
function elementInViewport(el) {
83
+
var rect = el.getBoundingClientRect()
84
+
85
+
return (
86
+
rect.bottom > -450 &&
87
+
rect.top - 450 <
88
+
(innerHeight() ||
89
+
document.documentElement
90
+
.clientHeight) /* or $(window).height() */
91
+
)
92
+
}
93
+
94
+
function nullifyTransforms(el) {
95
+
if (!el) return null
96
+
97
+
//add sanity checks and default values
98
+
99
+
let { top, left, right, width, height } = el.getBoundingClientRect()
100
+
101
+
let transformArr = window
102
+
.getComputedStyle(el)
103
+
.transform.split(/\(|,|\)/)
104
+
.slice(1, -1)
105
+
.map((v) => parseFloat(v))
106
+
107
+
if (transformArr.length != 6) {
108
+
return el.getBoundingClientRect()
109
+
}
110
+
111
+
// 2D matrix
112
+
// need some math to apply inverse of matrix
113
+
// That is the matrix of the transformation of the element
114
+
var t = transformArr
115
+
let det = t[0] * t[3] - t[1] * t[2]
116
+
117
+
/*if (transformArr.length > 6)*/
118
+
//3D matrix
119
+
//haven't done the calculation to apply inverse of 4x4 matrix
120
+
121
+
return {
122
+
width: width / t[0],
123
+
height: height / t[3],
124
+
left: (left * t[3] - top * t[2] + t[2] * t[5] - t[4] * t[3]) / det,
125
+
right: (right * t[3] - top * t[2] + t[2] * t[5] - t[4] * t[3]) / det,
126
+
top: (-left * t[1] + top * t[0] + t[4] * t[1] - t[0] * t[5]) / det,
127
+
}
128
+
}
129
+
130
+
export class Rellax {
131
+
constructor() {
132
+
this.blocks = []
133
+
this.oldPosY = false
134
+
135
+
this.intersectionObserver = new IntersectionObserver(
136
+
(entries) => {
137
+
entries.map(
138
+
({ target: el, isIntersecting, intersectionRatio }) => {
139
+
let blocks = this.blocks.filter(
140
+
({ fitInsideContainer, el: blockEl }) =>
141
+
blockEl.closest('svg')
142
+
? blockEl.closest('svg') === el
143
+
: fitInsideContainer === el ||
144
+
blockEl === el
145
+
)
146
+
147
+
let hasNewBlock = false
148
+
149
+
this.blocks = this.blocks.map((block) => {
150
+
const isThisBlock = block.el.closest('svg')
151
+
? block.el.closest('svg') === el
152
+
: block.fitInsideContainer === el ||
153
+
block.el === el
154
+
155
+
if (!isThisBlock) {
156
+
return block
157
+
}
158
+
159
+
hasNewBlock = true
160
+
161
+
return createBlock({
162
+
...block,
163
+
isVisible:
164
+
isIntersecting &&
165
+
block.parallaxBehavior.indexOf(
166
+
getCurrentScreen({ withTablet: true })
167
+
) > -1,
168
+
})
169
+
})
170
+
171
+
if (hasNewBlock) {
172
+
this.oldPosY = false
173
+
this.animate()
174
+
}
175
+
}
176
+
)
177
+
},
178
+
{
179
+
rootMargin: '450px',
180
+
}
181
+
)
182
+
183
+
// Start the loop
184
+
this.update()
185
+
186
+
// The loop does nothing if the scrollPosition did not change
187
+
// so call animate to make sure every element has their transforms
188
+
this.animate()
189
+
}
190
+
191
+
removeEl({ el }) {
192
+
el.removeAttribute('style')
193
+
this.blocks = this.blocks.filter(({ el: e }) => e !== el)
194
+
}
195
+
196
+
addEl({
197
+
el,
198
+
speed,
199
+
fitInsideContainer = null,
200
+
shouldSetHeightToIncrease = true,
201
+
parallaxBehavior = 'desktop:tablet:mobile',
202
+
}) {
203
+
if (fitInsideContainer) {
204
+
this.intersectionObserver.observe(fitInsideContainer)
205
+
} else {
206
+
this.intersectionObserver.observe(
207
+
el.closest('svg') ? el.closest('svg') : el
208
+
)
209
+
}
210
+
211
+
this.blocks.push(
212
+
createBlock({
213
+
el,
214
+
speed,
215
+
fitInsideContainer,
216
+
isVisible:
217
+
elementInViewport(
218
+
fitInsideContainer ? fitInsideContainer : el
219
+
) &&
220
+
parallaxBehavior.indexOf(
221
+
getCurrentScreen({ withTablet: true })
222
+
) > -1,
223
+
224
+
shouldSetHeightToIncrease,
225
+
parallaxBehavior,
226
+
})
227
+
)
228
+
}
229
+
230
+
update() {
231
+
if (!this.oldPosY && this.oldPosY !== 0) {
232
+
this.animate()
233
+
}
234
+
235
+
if (this.setPosition()) {
236
+
this.animate()
237
+
}
238
+
239
+
requestAnimationFrame(this.update.bind(this))
240
+
}
241
+
242
+
setPosition() {
243
+
if (this.blocks.length === 0) return false
244
+
245
+
let old = this.oldPosY
246
+
this.oldPosY = pageYOffset
247
+
248
+
return old != pageYOffset
249
+
}
250
+
251
+
animate() {
252
+
this.blocks.map((block) => {
253
+
if (!block.isVisible) {
254
+
block.el.removeAttribute('style')
255
+
return
256
+
}
257
+
258
+
var percentage =
259
+
(pageYOffset - block.top + innerHeight()) /
260
+
(block.height + innerHeight())
261
+
262
+
let { top, height } = nullifyTransforms(
263
+
block.fitInsideContainer ? block.fitInsideContainer : block.el
264
+
)
265
+
266
+
if (!height) {
267
+
height = (
268
+
block.fitInsideContainer
269
+
? block.fitInsideContainer
270
+
: block.el
271
+
).getBoundingClientRect().height
272
+
}
273
+
274
+
const newPercentage =
275
+
1 -
276
+
(top +
277
+
(block.el.dataset.percentage &&
278
+
parseInt(block.el.dataset.percentage, 10) === 0
279
+
? 0
280
+
: height / 2)) /
281
+
innerHeight()
282
+
283
+
// Subtracting initialize value, so element stays in same spot as HTML
284
+
var position =
285
+
updatePosition(
286
+
block.fitInsideContainer ? percentage : newPercentage,
287
+
block.speed
288
+
) -
289
+
updatePosition(
290
+
block.el.dataset.percentage
291
+
? parseInt(block.el.dataset.percentage, 10)
292
+
: 0.5,
293
+
block.speed
294
+
)
295
+
296
+
// Move that element
297
+
block.el.style.transform = `translate3d(0, ${position}px, 0)`
298
+
})
299
+
}
300
+
}
301
+