simedkom/public/js/home/vendors/interactive-portfolio.js

401 lines
11 KiB
JavaScript

/*!
Carto - Interactive portfolio
Created by ThemeZaa
!*/
$(function() {
"use strict";
const container = document.getElementById("stickyImgContainer");
if (typeof (container) != 'undefined' && container != null) {
const sliders = document.querySelector(".slides").querySelectorAll(".slide")
const slidesData = Array.from(sliders).map(item => {
return {
image: "",
title: "title1",
meta: ""
}
})
const createEleWithClass = (tag, className) => {
const ele = document.createElement(tag);
ele.className = className;
return ele;
};
class Slides {
constructor(data) {
this.data = document.querySelectorAll(".slide");
this.container = document.querySelector(".slides");
this.currentIdx = 0;
this.slides = document.querySelectorAll(".slide");
}
mount(container) {
container.appendChild(this.container);
let activeIndex = 0;
for (let i = 0; i < this.slides.length; i++) {
if (activeIndex === i) {
this.slides[i].classList.remove("next");
this.slides[i].classList.remove("prev");
this.slides[i].classList.add("show-meta");
document.querySelector(".bg-overlay").style.backgroundImage = `url("${this.slides[i].dataset.bg}")`
} else {
if (activeIndex > i) {
this.slides[i].classList.remove("next");
this.slides[i].classList.add("prev");
} else {
this.slides[i].classList.add("next");
this.slides[i].classList.remove("prev");
}
}
}
}
onActiveIndexChange(activeIndex) {
this.currentIdx = activeIndex;
for (let i = 0; i < this.slides.length; i++) {
if (activeIndex === i) {
this.slides[i].classList.remove("next");
this.slides[i].classList.remove("prev");
document.querySelector(".bg-overlay").style.backgroundImage = `url("${this.slides[i].dataset.bg}")`
} else {
if (activeIndex > i) {
this.slides[i].classList.remove("next");
this.slides[i].classList.add("prev");
} else {
this.slides[i].classList.add("next");
this.slides[i].classList.remove("prev");
}
}
}
}
onMove(indexFloat) {
this.container.style.transform = `translateY(${(indexFloat * 100) /
this.slides.length}%)`;
}
appear() {
this.container.classList.add("scrolling");
container.classList.add("scrolling");
this.slides[this.currentIdx].classList.remove("show-meta");
}
disperse(activeIndex) {
this.currentIdx = activeIndex;
this.slides[this.currentIdx].classList.add("show-meta");
this.container.classList.remove("scrolling");
container.classList.remove("scrolling");
for (let index = 0; index < this.data.length; index++) {
if (index > activeIndex) {
this.slides[index].classList.add("next");
this.slides[index].classList.remove("prev");
} else if (index < activeIndex) {
this.slides[index].classList.remove("next");
this.slides[index].classList.add("prev");
} else {
this.slides[index].classList.remove("next");
this.slides[index].classList.remove("prev");
}
}
}
}
class Grab {
constructor({
indexSize,
onIndexChange,
onGrabStart,
onGrabMove,
onGrabEnd
}) {
this.onGrabEnd = onGrabEnd;
this.onGrabStart = onGrabStart;
this.onGrabMove = onGrabMove;
this.scroll = {
start: 0,
current: 0,
initial: 0
};
this.listen("mousedown", this.onMouseDown.bind(this));
this.listen("mousemove", this.onMouseMove.bind(this));
this.listen("mouseup", this.onMouseUp.bind(this));
this.listen("touchstart", this.onMouseDown.bind(this), true);
this.listen("touchmove", this.onMouseMove.bind(this), true);
this.listen(["touchend", "touchcancel"], this.onMouseUp.bind(this), true);
}
listen(events, grabListener, isTouch) {
const _this = this;
let mouseListener = function (ev) {
if (ev.type === "mouseout" && ev.relatedTarget != null) return;
grabListener({
y: ev.clientY
});
};
let touchListener = function (ev) {
grabListener({
y: ev.targetTouches[0] ? ev.targetTouches[0].clientY : null
});
};
let listener = mouseListener;
if (isTouch) {
listener = touchListener;
}
if (Array.isArray(events)) {
for (let i = 0; i < events.length; i++) {
window.addEventListener(events[i], listener, false);
}
} else {
window.addEventListener(events, function (event) {
if (event.target.closest(".stickyImageContainer") === container) {
listener(event);
} else {
_this.onMouseUp()
}
}, false);
}
}
onMouseDown(position) {
this.scroll.inital = this.scroll.current;
this.scroll.start = position.y;
this.scroll.current = position.y;
this.scroll.delta = this.scroll.current - this.scroll.start;
this.onGrabStart({
delta: this.scroll.delta,
direction: Math.abs(this.scroll.delta),
current: this.scroll.current,
start: this.scroll.start
});
}
onMouseMove(position) {
if (this.scroll.start) {
this.scroll.current = position.y;
this.scroll.delta = this.scroll.current - this.scroll.start;
this.onGrabMove({
delta: this.scroll.delta,
direction: Math.abs(this.scroll.delta),
current: this.scroll.current,
start: this.scroll.start
});
}
}
onMouseUp() {
if (this.scroll.start) {
this.onGrabEnd({
delta: this.scroll.delta,
direction: Math.abs(this.scroll.delta),
current: this.scroll.current,
start: this.scroll.start
});
this.scroll.start = null;
this.scroll.current = null;
this.scroll.delta = null;
}
}
}
const reach = function ({ from, to, restDelta = 0.01 }) {
let current = Object.assign({}, from);
let keys = Object.keys(from);
let raf = {
current: null
};
let _update = function (update, complete) {
if (keys.length === 0) {
cancelAnimationFrame(raf.current);
raf.current = null;
complete(current);
return;
}
let cacheKeys = keys.slice();
for (var i = keys.length, val, key; i >= 0; i--) {
key = keys[i];
val = current[key] + (to[key] - current[key]) * 0.1;
if (Math.abs(to[key] - val) < restDelta) {
current[key] = to[key];
// Remove key
keys.splice(i, 1);
// Move i down by pne
i--;
} else {
current[key] = val;
}
}
update(current);
raf.current = requestAnimationFrame(_update);
};
return {
start: function ({
update,
complete
}) {
_update = _update.bind(null, update, complete);
raf.current = requestAnimationFrame(_update);
return {
stop: function () {
cancelAnimationFrame(raf.current);
raf.current = null;
}
};
}
};
};
function Showcase(data, options = {}) {
this.data = data;
this.progress = 0;
this.direction = 1;
this.waveIntensity = 0;
this.options = options;
this.index = {
target: 0,
current: 0,
initial: 0,
scrollSize: window.innerHeight / 6,
active: 0
};
this.follower = {
x: 0,
y: 0
};
this.followerSpring = null;
this.slidesSpring = null;
this.grab = new Grab({
onGrabStart: this.onGrabStart.bind(this),
onGrabMove: this.onGrabMove.bind(this),
onGrabEnd: this.onGrabEnd.bind(this)
});
}
function clamp(num, min, max) {
return Math.max(min, Math.min(num, max));
}
Showcase.prototype.onGrabMove = function (scroll) {
this.index.target = clamp(
this.index.initial + scroll.delta / this.index.scrollSize,
-this.data.length + 0.51,
0.49
);
const index = clamp(Math.round(-this.index.target), 0, this.data.length - 1);
if (this.index.active !== index) {
this.index.active = index;
if (this.options.onActiveIndexChange) {
this.options.onActiveIndexChange(this.index.active);
}
}
if (this.slidesPop) {
this.slidesPop.stop();
}
this.slidesPop = reach({
from: {
index: this.index.current
},
to: {
index: this.index.target
},
restDelta: 0.001
}).start({
update: val => {
if (this.options.onIndexChange) {
this.options.onIndexChange(val.index);
}
this.index.current = val.index;
},
complete: val => {
if (this.options.onIndexChange) {
this.options.onIndexChange(val.index);
}
this.index.current = val.index;
}
});
};
Showcase.prototype.onGrabStart = function () {
if (this.options.onZoomOutStart) {
this.options.onZoomOutStart({
activeIndex: this.index.active
});
}
this.index.initial = this.index.current;
};
Showcase.prototype.snapCurrentToActiveIndex = function () {
if (this.slidesPop) {
this.slidesPop.stop();
}
this.slidesPop = reach({
from: {
index: this.index.current
},
to: {
index: Math.round(this.index.target)
},
restDelta: 0.001
}).start({
complete: () => { },
update: val => {
// this.slides.onMove(val);
if (this.options.onIndexChange) {
this.options.onIndexChange(val.index);
}
this.index.current = val.index;
}
});
};
Showcase.prototype.onGrabEnd = function () {
if (this.options.onFullscreenStart) {
this.options.onFullscreenStart({
activeIndex: this.index.active
});
this.snapCurrentToActiveIndex();
}
};
Showcase.prototype.onResize = function () {
};
const slides = new Slides();
const showcase = new Showcase(slidesData, {
onActiveIndexChange: activeIndex => {
slides.onActiveIndexChange(activeIndex);
},
onIndexChange: index => {
slides.onMove(index);
},
onZoomOutStart: ({ activeIndex }) => {
slides.appear();
},
onZoomOutFinish: ({ activeIndex }) => { },
onFullscreenStart: ({ activeIndex }) => {
slides.disperse(activeIndex);
},
onFullscreenFinish: ({ activeIndex }) => { }
});
slides.mount(container);
}
});