Diff: STRATO-apps/wordpress_03/app/wp-content/themes/blocksy/static/js/frontend/parallax/rellax.js

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
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 +