PluginProbe ʕ •ᴥ•ʔ
Spider Elements – Premium Elementor Widgets & Addons Library / 1.5.0
Spider Elements – Premium Elementor Widgets & Addons Library v1.5.0
trunk 1.0.0 1.1.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.7.0 1.8.0 1.9.0
spider-elements / assets / vendors / diagonal / diagonal.slideshow.js
spider-elements / assets / vendors / diagonal Last commit date
TweenMax.min.js 1 year ago charming.min.js 1 year ago diagonal.css 1 year ago diagonal.slideshow.js 1 year ago
diagonal.slideshow.js
750 lines
1 /**
2 * demo.js
3 * http://www.codrops.com
4 *
5 * Licensed under the MIT license.
6 * http://www.opensource.org/licenses/mit-license.php
7 *
8 * Copyright 2018, Codrops
9 * http://www.codrops.com
10 */
11 {
12 // From http://www.quirksmode.org/js/events_properties.html#position
13 // Get the mouse position.
14 const getMousePos = (e) => {
15 let posx = 0;
16 let posy = 0;
17 if (!e) e = window.event;
18 if (e.pageX || e.pageY) {
19 posx = e.pageX;
20 posy = e.pageY;
21 } else if (e.clientX || e.clientY) {
22 posx =
23 e.clientX +
24 document.body.scrollLeft +
25 document.documentElement.scrollLeft;
26 posy =
27 e.clientY +
28 document.body.scrollTop +
29 document.documentElement.scrollTop;
30 }
31 return { x: posx, y: posy };
32 };
33 // Gets a random integer.
34 const getRandomInt = (min, max) =>
35 Math.floor(Math.random() * (max - min + 1)) + min;
36 // Equation of a line (y = mx + b ).
37 const lineEq = (y2, y1, x2, x1, currentVal) => {
38 const m = (y2 - y1) / (x2 - x1);
39 const b = y1 - m * x1;
40 return m * currentVal + b;
41 };
42
43 // Some random chars.
44 const chars = [
45 "$",
46 "%",
47 "#",
48 "&",
49 "=",
50 "*",
51 "a",
52 "b",
53 "c",
54 "d",
55 "e",
56 "f",
57 "g",
58 "h",
59 "i",
60 "j",
61 "k",
62 "l",
63 "m",
64 "n",
65 "o",
66 "p",
67 "q",
68 "r",
69 "s",
70 "t",
71 "u",
72 "v",
73 "w",
74 "x",
75 "y",
76 "z",
77 ".",
78 ":",
79 ",",
80 "^",
81 ];
82 const charsTotal = chars.length;
83
84 // Randomize letters function. Used when navigating the slideshow to switch the curretn slide´s texts.
85 const randomizeLetters = (letters) => {
86 return new Promise((resolve, reject) => {
87 const lettersTotal = letters.length;
88 let cnt = 0;
89
90 letters.forEach((letter, pos) => {
91 let loopTimeout;
92 const loop = () => {
93 letter.innerHTML = chars[getRandomInt(0, charsTotal - 1)];
94 loopTimeout = setTimeout(loop, getRandomInt(50, 500));
95 };
96 loop();
97
98 const timeout = setTimeout(() => {
99 clearTimeout(loopTimeout);
100 letter.style.opacity = 1;
101 letter.innerHTML = letter.dataset.initial;
102 ++cnt;
103 if (cnt === lettersTotal) {
104 resolve();
105 }
106 }, pos * lineEq(40, 0, 8, 200, lettersTotal));
107 });
108 });
109 };
110
111 // Hide each of the letters with random delays. Used when showing the current slide´s content.
112 const disassembleLetters = (letters) => {
113 return new Promise((resolve, reject) => {
114 const lettersTotal = letters.length;
115 let cnt = 0;
116
117 letters.forEach((letter, pos) => {
118 setTimeout(() => {
119 letter.style.opacity = 0;
120 ++cnt;
121 if (cnt === lettersTotal) {
122 resolve();
123 }
124 }, pos * 30);
125 });
126 });
127 };
128
129 // The Slide class.
130 class Slide {
131 constructor(el) {
132 this.DOM = { el: el };
133 // The image wrap element.
134 this.DOM.imgWrap = this.DOM.el.querySelector(".slide__img-wrap");
135 // The image element.
136 this.DOM.img = this.DOM.imgWrap.querySelector(".slide__img");
137 // The texts: the parent wrap, title, number and side text.
138 this.DOM.texts = {
139 wrap: this.DOM.el.querySelector(".slide__title-wrap"),
140 title: this.DOM.el.querySelector(".slide__title"),
141 number: this.DOM.el.querySelector(".slide__number"),
142 side: this.DOM.el.querySelector(".slide__side"),
143 };
144 // Split the title and side texts into spans, one per letter. Sort these so we can later animate then with the
145 // randomizeLetters or disassembleLetters functions when navigating and showing the content.
146 charming(this.DOM.texts.title);
147 charming(this.DOM.texts.side);
148 this.DOM.titleLetters = Array.from(
149 this.DOM.texts.title.querySelectorAll("span")
150 ).sort(() => 0.5 - Math.random());
151 this.DOM.sideLetters = Array.from(
152 this.DOM.texts.side.querySelectorAll("span")
153 ).sort(() => 0.5 - Math.random());
154 this.DOM.titleLetters.forEach(
155 (letter) => (letter.dataset.initial = letter.innerHTML)
156 );
157 this.DOM.sideLetters.forEach(
158 (letter) => (letter.dataset.initial = letter.innerHTML)
159 );
160 // Calculate the sizes of the image wrap.
161 this.calcSizes();
162 // And also the transforms needed per position.
163 // We have 5 different possible positions for a slide: center, bottom right, top left and outside the viewport (top left or bottom right).
164 this.calcTransforms();
165 // Init/Bind events.
166 this.initEvents();
167 }
168 // Gets the size of the image wrap.
169 calcSizes() {
170 this.width = this.DOM.imgWrap.offsetWidth;
171 this.height = this.DOM.imgWrap.offsetHeight;
172 }
173 // Gets the transforms per slide position.
174 calcTransforms() {
175 /*
176 Each position corresponds to the position of a given slide:
177 0: left top corner outside the viewport
178 1: left top corner (prev slide position)
179 2: center (current slide position)
180 3: right bottom corner (next slide position)
181 4: right bottom corner outside the viewport
182 5: left side, for when the content is shown
183 */
184 this.transforms = [
185 {
186 x: -1 * (winsize.width / 2 + this.width),
187 y: -1 * (winsize.height / 2 + this.height),
188 rotation: -30,
189 },
190 {
191 x: -1 * (winsize.width / 2 - this.width / 3),
192 y: -1 * (winsize.height / 2 - this.height / 3),
193 rotation: 0,
194 },
195 { x: 0, y: 0, rotation: 0 },
196 {
197 x: winsize.width / 2 - this.width / 3,
198 y: winsize.height / 2 - this.height / 3,
199 rotation: 0,
200 },
201 {
202 x: winsize.width / 2 + this.width,
203 y: winsize.height / 2 + this.height,
204 rotation: 30,
205 },
206 {
207 x: -1 * (winsize.width / 2 - this.width / 2 - winsize.width * 0.075),
208 y: 0,
209 rotation: 0,
210 },
211 ];
212 }
213 // Init events:
214 // Mouseevents for mousemove/tilt/scale on the current image, and window resize.
215 initEvents() {
216 this.mouseenterFn = () => {
217 if (!this.isPositionedCenter() || !allowTilt) return;
218 clearTimeout(this.mousetime);
219 this.mousetime = setTimeout(() => {
220 // Scale the image.
221 TweenMax.to(this.DOM.img, 0.8, {
222 ease: Power3.easeOut,
223 scale: 1.1,
224 });
225 }, 40);
226 };
227 this.mousemoveFn = (ev) =>
228 requestAnimationFrame(() => {
229 // Tilt the current slide.
230 if (!allowTilt || !this.isPositionedCenter()) return;
231 this.tilt(ev);
232 });
233 this.mouseleaveFn = (ev) =>
234 requestAnimationFrame(() => {
235 if (!allowTilt || !this.isPositionedCenter()) return;
236 clearTimeout(this.mousetime);
237
238 // Reset tilt and image scale.
239 TweenMax.to([this.DOM.imgWrap, this.DOM.texts.wrap], 1.8, {
240 ease: "Power4.easeOut",
241 x: 0,
242 y: 0,
243 rotationX: 0,
244 rotationY: 0,
245 });
246 TweenMax.to(this.DOM.img, 1.8, {
247 ease: "Power4.easeOut",
248 scale: 1,
249 });
250 });
251 // When resizing the window recalculate size and transforms, since both will depend on the window size.
252 this.resizeFn = () => {
253 this.calcSizes();
254 this.calcTransforms();
255 };
256 this.DOM.imgWrap.addEventListener("mouseenter", this.mouseenterFn);
257 this.DOM.imgWrap.addEventListener("mousemove", this.mousemoveFn);
258 this.DOM.imgWrap.addEventListener("mouseleave", this.mouseleaveFn);
259 window.addEventListener("resize", this.resizeFn);
260 }
261 // Tilt the image wrap and texts when mouse moving the current slide.
262 tilt(ev) {
263 const mousepos = getMousePos(ev);
264 // Document scrolls.
265 const docScrolls = {
266 left: document.body.scrollLeft + document.documentElement.scrollLeft,
267 top: document.body.scrollTop + document.documentElement.scrollTop,
268 };
269 const bounds = this.DOM.imgWrap.getBoundingClientRect();
270 // Mouse position relative to the main element (this.DOM.el).
271 const relmousepos = {
272 x: mousepos.x - bounds.left - docScrolls.left,
273 y: mousepos.y - bounds.top - docScrolls.top,
274 };
275
276 // Move the element from -20 to 20 pixels in both x and y axis.
277 // Rotate the element from -15 to 15 degrees in both x and y axis.
278 let t = { x: [-20, 20], y: [-20, 20] },
279 r = { x: [-15, 15], y: [-15, 15] };
280
281 const transforms = {
282 translation: {
283 x: ((t.x[1] - t.x[0]) / bounds.width) * relmousepos.x + t.x[0],
284 y: ((t.y[1] - t.y[0]) / bounds.height) * relmousepos.y + t.y[0],
285 },
286 rotation: {
287 x: ((r.x[1] - r.x[0]) / bounds.height) * relmousepos.y + r.x[0],
288 y: ((r.y[1] - r.y[0]) / bounds.width) * relmousepos.x + r.y[0],
289 },
290 };
291
292 // Move the image wrap.
293 TweenMax.to(this.DOM.imgWrap, 1.5, {
294 ease: "Power1.easeOut",
295 x: transforms.translation.x,
296 y: transforms.translation.y,
297 rotationX: transforms.rotation.x,
298 rotationY: transforms.rotation.y,
299 });
300
301 // Move the texts wrap.
302 TweenMax.to(this.DOM.texts.wrap, 1.5, {
303 ease: "Power1.easeOut",
304 x: -1 * transforms.translation.x,
305 y: -1 * transforms.translation.y,
306 });
307 }
308 // Positions one slide (left, right or current) in the viewport.
309 position(pos) {
310 TweenMax.set(this.DOM.imgWrap, {
311 x: this.transforms[pos].x,
312 y: this.transforms[pos].y,
313 rotationX: 0,
314 rotationY: 0,
315 opacity: 1,
316 rotationZ: this.transforms[pos].rotation,
317 });
318 }
319 // Sets it as current.
320 setCurrent(isContentOpen) {
321 this.isCurrent = true;
322 this.DOM.el.classList.add("slide--current", "slide--visible");
323 // Position it on the current´s position.
324 this.position(isContentOpen ? 5 : 2);
325 }
326 // Position the slide on the left side.
327 setLeft(isContentOpen) {
328 this.isRight = this.isCurrent = false;
329 this.isLeft = true;
330 this.DOM.el.classList.add("slide--visible");
331 // Position it on the left position.
332 this.position(isContentOpen ? 0 : 1);
333 }
334 // Position the slide on the right side.
335 setRight(isContentOpen) {
336 this.isLeft = this.isCurrent = false;
337 this.isRight = true;
338 this.DOM.el.classList.add("slide--visible");
339 // Position it on the right position.
340 this.position(isContentOpen ? 4 : 3);
341 }
342 // Check if the slide is positioned on the right side (if it´s the next slide in the slideshow).
343 isPositionedRight() {
344 return this.isRight;
345 }
346 // Check if the slide is positioned on the left side (if it´s the previous slide in the slideshow).
347 isPositionedLeft() {
348 return this.isLeft;
349 }
350 // Check if the slide is the current one.
351 isPositionedCenter() {
352 return this.isCurrent;
353 }
354 // Reset classes and state.
355 reset() {
356 this.isRight = this.isLeft = this.isCurrent = false;
357 this.DOM.el.classList = "slide";
358 }
359 hide() {
360 TweenMax.set(this.DOM.imgWrap, {
361 x: 0,
362 y: 0,
363 rotationX: 0,
364 rotationY: 0,
365 rotationZ: 0,
366 opacity: 0,
367 });
368 }
369 // Moves a slide to a specific position defined in settings.position.
370 // Also, moves it from position settings.from and if we need to reset the image scale when moving the slide then settings.resetImageScale should be true.
371 moveToPosition(settings) {
372 return new Promise((resolve, reject) => {
373 /*
374 Moves the slide to a specific position:
375 -2: left top corner outside the viewport
376 -1: left top corner (prev slide position)
377 0: center (current slide position)
378 1: right bottom corner (next slide position)
379 2: right bottom corner outside the viewport
380 3: left side, for when the content is shown
381 */
382 TweenMax.to(this.DOM.imgWrap, 0.8, {
383 ease: Power4.easeInOut,
384 delay: settings.delay || 0,
385 startAt:
386 settings.from !== undefined
387 ? {
388 x: this.transforms[settings.from + 2].x,
389 y: this.transforms[settings.from + 2].y,
390 rotationX: 0,
391 rotationY: 0,
392 rotationZ: this.transforms[settings.from + 2].rotation,
393 }
394 : {},
395 x: this.transforms[settings.position + 2].x,
396 y: this.transforms[settings.position + 2].y,
397 rotationX: 0,
398 rotationY: 0,
399 rotationZ: this.transforms[settings.position + 2].rotation,
400 onStart:
401 settings.from !== undefined
402 ? () => TweenMax.set(this.DOM.imgWrap, { opacity: 1 })
403 : null,
404 onComplete: resolve,
405 });
406
407 // Reset image scale when showing the content of the current slide.
408 if (settings.resetImageScale) {
409 TweenMax.to(this.DOM.img, 0.8, {
410 ease: Power4.easeInOut,
411 scale: 1,
412 });
413 }
414 });
415 }
416 // Hides the current slide´s texts.
417 hideTexts(animation = false) {
418 if (animation) {
419 disassembleLetters(this.DOM.titleLetters).then(() =>
420 TweenMax.set(this.DOM.texts.wrap, { opacity: 0 })
421 );
422 disassembleLetters(this.DOM.sideLetters).then(() =>
423 TweenMax.set(this.DOM.texts.side, { opacity: 0 })
424 );
425 } else {
426 TweenMax.set(this.DOM.texts.wrap, { opacity: 0 });
427 TweenMax.set(this.DOM.texts.side, { opacity: 0 });
428 }
429 }
430 // Shows the current slide´s texts.
431 showTexts(animation = true) {
432 TweenMax.set(this.DOM.texts.wrap, { opacity: 1 });
433 TweenMax.set(this.DOM.texts.side, { opacity: 1 });
434
435 if (animation) {
436 randomizeLetters(this.DOM.titleLetters);
437 randomizeLetters(this.DOM.sideLetters);
438 TweenMax.to(this.DOM.texts.number, 0.6, {
439 ease: Elastic.easeOut.config(1, 0.5),
440 startAt: { x: "-10%", opacity: 0 },
441 x: "0%",
442 opacity: 1,
443 });
444 }
445 }
446 }
447
448 // The Content class. Represents one content item per slide.
449 class Content {
450 constructor(el) {
451 this.DOM = { el: el };
452 this.DOM.number = this.DOM.el.querySelector(".content__number");
453 this.DOM.title = this.DOM.el.querySelector(".content__title");
454 this.DOM.subtitle = this.DOM.el.querySelector(".content__subtitle");
455 this.DOM.text = this.DOM.el.querySelector(".content__text");
456 this.DOM.backCtrl =
457 this.DOM.el.parentNode.querySelector(".content__close");
458 this.DOM.backCtrl.addEventListener("click", () =>
459 slideshow.hideContent()
460 );
461 }
462 show() {
463 this.DOM.el.classList.add("content__item--current");
464
465 TweenMax.staggerTo(
466 [
467 this.DOM.backCtrl,
468 this.DOM.number,
469 this.DOM.title,
470 this.DOM.subtitle,
471 this.DOM.text,
472 ],
473 0.8,
474 {
475 ease: Power4.easeOut,
476 delay: 0.4,
477 opacity: 1,
478 startAt: { y: 40 },
479 y: 0,
480 },
481 0.05
482 );
483 }
484 hide() {
485 this.DOM.el.classList.remove("content__item--current");
486
487 TweenMax.staggerTo(
488 [
489 this.DOM.backCtrl,
490 this.DOM.number,
491 this.DOM.title,
492 this.DOM.subtitle,
493 this.DOM.text,
494 ].reverse(),
495 0.3,
496 {
497 ease: Power3.easeIn,
498 opacity: 0,
499 y: 10,
500 },
501 0.01
502 );
503 }
504 }
505
506 // The Slideshow class.
507 class Slideshow {
508 constructor(el) {
509 this.DOM = { el: el };
510 // The slides.
511 this.slides = [];
512 Array.from(this.DOM.el.querySelectorAll(".slide")).forEach((slideEl) =>
513 this.slides.push(new Slide(slideEl))
514 );
515 // The total number of slides.
516 this.slidesTotal = this.slides.length;
517 // At least 4 slides to continue...
518 if (this.slidesTotal < 4) {
519 return false;
520 }
521 // Current slide position.
522 this.current = 0;
523 this.DOM.deco = this.DOM.el.querySelector(".slideshow__deco");
524
525 this.contents = [];
526 Array.from(
527 document.querySelectorAll(".content > .content__item")
528 ).forEach((contentEl) => this.contents.push(new Content(contentEl)));
529
530 // Set the current/next/previous slides.
531 this.render();
532 this.currentSlide.showTexts(false);
533 // Init/Bind events.
534 this.initEvents();
535 }
536 render() {
537 // The current, next, and previous slides.
538 this.currentSlide = this.slides[this.current];
539 this.nextSlide =
540 this.slides[
541 this.current + 1 <= this.slidesTotal - 1 ? this.current + 1 : 0
542 ];
543 this.prevSlide =
544 this.slides[
545 this.current - 1 >= 0 ? this.current - 1 : this.slidesTotal - 1
546 ];
547 this.currentSlide.setCurrent();
548 this.nextSlide.setRight();
549 this.prevSlide.setLeft();
550 }
551 initEvents() {
552 // Clicking the next and previous slide starts the navigation / clicking the current shows its content..
553 this.clickFn = (slide) => {
554 if (slide.isPositionedRight()) {
555 this.navigate("next");
556 } else if (slide.isPositionedLeft()) {
557 this.navigate("prev");
558 } else {
559 this.showContent();
560 }
561 };
562 for (let slide of this.slides) {
563 slide.DOM.imgWrap.addEventListener("click", () => this.clickFn(slide));
564 }
565
566 this.resizeFn = () => {
567 // Reposition the slides.
568 this.nextSlide.setRight(this.isContentOpen);
569 this.prevSlide.setLeft(this.isContentOpen);
570 this.currentSlide.setCurrent(this.isContentOpen);
571
572 if (this.isContentOpen) {
573 TweenMax.set(this.DOM.deco, {
574 scaleX: winsize.width / this.DOM.deco.offsetWidth,
575 scaleY: winsize.height / this.DOM.deco.offsetHeight,
576 x: -20,
577 y: 20,
578 });
579 }
580 };
581 window.addEventListener("resize", this.resizeFn);
582 }
583 showContent() {
584 if (this.isContentOpen || this.isAnimating) return;
585 allowTilt = false;
586 this.isContentOpen = true;
587 this.DOM.el.classList.add("slideshow--previewopen");
588 TweenMax.to(this.DOM.deco, 0.8, {
589 ease: Power4.easeInOut,
590 scaleX: winsize.width / this.DOM.deco.offsetWidth,
591 scaleY: winsize.height / this.DOM.deco.offsetHeight,
592 x: -20,
593 y: 20,
594 });
595 // Move away right/left slides.
596 this.prevSlide.moveToPosition({ position: -2 });
597 this.nextSlide.moveToPosition({ position: 2 });
598 // Position the current slide and reset its image scale value.
599 this.currentSlide.moveToPosition({ position: 3, resetImageScale: true });
600 // Show content and back arrow (to close the content).
601 this.contents[this.current].show();
602 // Hide texts.
603 this.currentSlide.hideTexts(true);
604 }
605 hideContent() {
606 if (!this.isContentOpen || this.isAnimating) return;
607
608 this.DOM.el.classList.remove("slideshow--previewopen");
609
610 // Hide content.
611 this.contents[this.current].hide();
612
613 TweenMax.to(this.DOM.deco, 0.8, {
614 ease: Power4.easeInOut,
615 scaleX: 1,
616 scaleY: 1,
617 x: 0,
618 y: 0,
619 });
620 // Move in right/left slides.
621 this.prevSlide.moveToPosition({ position: -1 });
622 this.nextSlide.moveToPosition({ position: 1 });
623 // Position the current slide.
624 this.currentSlide.moveToPosition({ position: 0 }).then(() => {
625 allowTilt = true;
626 this.isContentOpen = false;
627 });
628 // Show texts.
629 this.currentSlide.showTexts();
630 }
631 // Animates the element behind the current slide.
632 bounceDeco(direction, delay) {
633 TweenMax.to(this.DOM.deco, 0.4, {
634 ease: "Power2.easeIn",
635 delay: delay + delay * 0.2,
636 x: direction === "next" ? -40 : 40,
637 y: direction === "next" ? -40 : 40,
638 onComplete: () => {
639 TweenMax.to(this.DOM.deco, 0.6, {
640 //ease: Elastic.easeOut.config(1, 0.65),
641 ease: "Power2.easeOut",
642 x: 0,
643 y: 0,
644 });
645 },
646 });
647 }
648 // Navigate the slideshow.
649 navigate(direction) {
650 // If animating return.
651 if (this.isAnimating) return;
652 this.isAnimating = true;
653 allowTilt = false;
654
655 const upcomingPos =
656 direction === "next"
657 ? this.current < this.slidesTotal - 2
658 ? this.current + 2
659 : Math.abs(this.slidesTotal - 2 - this.current)
660 : this.current >= 2
661 ? this.current - 2
662 : Math.abs(this.slidesTotal - 2 + this.current);
663
664 this.upcomingSlide = this.slides[upcomingPos];
665
666 // Update current.
667 this.current =
668 direction === "next"
669 ? this.current < this.slidesTotal - 1
670 ? this.current + 1
671 : 0
672 : this.current > 0
673 ? this.current - 1
674 : this.slidesTotal - 1;
675
676 // Move slides (the previous, current, next and upcoming slide).
677 this.prevSlide
678 .moveToPosition({
679 position: direction === "next" ? -2 : 0,
680 delay: direction === "next" ? 0 : 0.14,
681 })
682 .then(() => {
683 if (direction === "next") {
684 this.prevSlide.hide();
685 }
686 });
687
688 this.currentSlide.moveToPosition({
689 position: direction === "next" ? -1 : 1,
690 delay: 0.07,
691 });
692 this.currentSlide.hideTexts();
693
694 this.bounceDeco(direction, 0.07);
695
696 this.nextSlide
697 .moveToPosition({
698 position: direction === "next" ? 0 : 2,
699 delay: direction === "next" ? 0.14 : 0,
700 })
701 .then(() => {
702 if (direction === "prev") {
703 this.nextSlide.hide();
704 }
705 });
706
707 if (direction === "next") {
708 this.nextSlide.showTexts();
709 } else {
710 this.prevSlide.showTexts();
711 }
712
713 this.upcomingSlide
714 .moveToPosition({
715 position: direction === "next" ? 1 : -1,
716 from: direction === "next" ? 2 : -2,
717 delay: 0.21,
718 })
719 .then(() => {
720 // Reset classes.
721 [this.nextSlide, this.currentSlide, this.prevSlide].forEach((slide) =>
722 slide.reset()
723 );
724 this.render();
725 allowTilt = true;
726 this.isAnimating = false;
727 });
728 }
729 }
730
731 // Window sizes.
732 let winsize;
733 const calcWinsize = () =>
734 (winsize = { width: window.innerWidth, height: window.innerHeight });
735 calcWinsize();
736 window.addEventListener("resize", calcWinsize);
737
738 let allowTilt = true;
739
740 // Init slideshow.
741 const slideshow = new Slideshow(document.querySelector(".slideshow"));
742
743 // Preload all the images in the page..
744 const loader = document.querySelector(".loader");
745 imagesLoaded(
746 document.querySelectorAll(".slide__img"),
747 { background: true },
748 () => document.body.classList.remove("loading")
749 );
750 }