<script>
class PIXIScene {
constructor(container) {
this.container = container;
if (!this.container) return;
this.init();
}
init() {
this.state();
this.setup();
this.animate();
}
state() {
this.isAnimating = false;
this.currentIndex = 0;
this.slides = [];
this.dom = {
next: document.querySelector('.slider__count'),
current: document.querySelector('.slider__count') };
}
setup() {
this.app = new PIXI.Application({
width: this.viewport.width,
height: this.viewport.height,
resolution: window.devicePixelRatio,
autoDensity: true,
autoResize: true,
transparent: true });
this.loadImages();
}
loadImages() {
//Getting the original images
this.originalImages = [...this.container.querySelectorAll("img")];
this.imageSrc = this.originalImages.map(image => image.getAttribute("src"));
//Clearing the container & appending the canvas into it
this.container.innerHTML = "";
this.container.appendChild(this.app.view);
//Defining the loader
const loader = new PIXI.Loader();
//Adding the image src
this.images = [...this.imageSrc];
//Loading each image
this.images.forEach((image, i) => {
loader.add(image, this.images[i]);
});
loader.load((loader, resources) => {
this.resources = resources;
this.createSlider();
});
}
createSlider() {
//Container for all the images
this.slider = new PIXI.Container();
this.slider.width = this.app.screen.width;
this.slider.height = this.app.screen.height;
this.app.stage.addChild(this.slider);
//Defining the area for the filter
this.clipRect = new PIXI.Rectangle(
0,
0,
this.app.screen.width,
this.app.screen.height);
this.slider.filterArea = this.clipRect;
this.app.stage.interactive = true;
this.addSlides();
this.createFilters();
this.slider.filters = [this.displacementFilter];
this.events();
}
addSlides() {
let i = 0;
Object.keys(this.resources).forEach(key => {
const slide = new PIXI.Sprite(this.resources[key].texture);
//Setting initial slide position
slide.width = this.app.screen.width;
slide.height = this.app.screen.height;
slide.y = 0;
slide.x = i === 0 ? 0 : -this.app.screen.width;
//Adding all slides to the array in state
this.slides[i] = slide;
this.slider.addChild(slide);
i++;
});
}
createFilters() {
this.displacement = new PIXI.Sprite.from(
"https://static.tildacdn.com/tild3337-3431-4061-a364-303961356434/Frame_24.jpg");
this.displacement.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
this.displacementFilter = new PIXI.filters.DisplacementFilter(this.displacement, 0);
this.RGBFilter = new PIXI.filters.RGBSplitFilter([0, 0], [0, 0], [0, 0]);
return this.displacementFilter, this.RGBFilter;
}
nextSlide() {
if (this.nextButton.getAttribute('disabled') || this.isAnimating) return false;
this.prevButton.removeAttribute('disabled');
if (this.currentIndex + 2 >= this.images.length) {
this.nextButton.setAttribute('disabled', 'disabled');
}
const currentSlide = this.slides[this.currentIndex];
const nextSlide = this.slides[this.currentIndex + 1];
this.dom.next.textContent = '0' + (this.currentIndex + 2);
const tl = gsap.timeline({
onStart: () => {
this.isAnimating = true;
},
onComplete: () => {
this.currentIndex++;
this.isAnimating = false;
} });
tl.
to(currentSlide, {
x: -this.app.screen.width,
duration: 1.5,
ease: 'Expo.easeInOut' },
0).
fromTo(nextSlide, {
x: this.app.screen.width },
{
x: 0,
ease: 'Expo.easeInOut',
duration: 1.5 },
0).
to(this.displacementFilter.scale, {
x: 100,
y: 100,
duration: 1 },
0).
to(this.displacementFilter.scale, {
duration: 1,
x: 0,
y: 0 },
0.5).
set(this.dom.current, {
y: 0 }).
set(this.dom.next, {
y: '-100%' },
0).
to(this.dom.current, {
y: '100%' },
0).
to(this.dom.next, {
y: 0 },
'-=1');
return tl;
}
prevSlide() {
if (this.prevButton.getAttribute('disabled') || this.isAnimating) return false;
this.nextButton.removeAttribute('disabled');
if (this.currentIndex - 2 < 0) {
this.prevButton.setAttribute('disabled', 'disabled');
}
this.dom.next.textContent = '0' + this.currentIndex;
const tl = gsap.timeline({
onStart: () => {
this.isAnimating = true;
},
onComplete: () => {
this.currentIndex--;
this.isAnimating = false;
} });
const currentSlide = this.slides[this.currentIndex];
const prevSlide = this.slides[this.currentIndex - 1];
tl.
to(currentSlide, {
x: this.app.screen.width,
duration: 1.5,
ease: 'Expo.easeInOut' },
0).
fromTo(prevSlide, {
x: -this.app.screen.width },
{
x: 0,
ease: 'Expo.easeInOut',
duration: 1.5 },
0).
to(this.displacementFilter.scale, {
x: 100,
y: 100,
duration: 1 },
0).
to(this.displacementFilter.scale, {
duration: 1,
x: 0,
y: 0 },
0.5).
set(this.dom.current, {
y: 0 }).
set(this.dom.next, {
y: '100%' },
0).
to(this.dom.current, {
y: '-100%' },
0).
to(this.dom.next, {
y: 0 },
'-=1');
return tl;
}
events() {
this.nextButton = document.querySelector(".slider__next");
this.prevButton = document.querySelector(".slider__prev");
this.nextButton.addEventListener("click", this.nextSlide.bind(this));
this.prevButton.addEventListener("click", this.prevSlide.bind(this));
}
animate() {
requestAnimationFrame(() => {
this.animate();
});
this.app.render();
}
get viewport() {
const width = this.container.clientWidth;
const height = this.container.clientHeight;
return {
width,
height };
}}
const slideshowCanvas = document.querySelector(".slider__canvas");
const scene = new PIXIScene(slideshowCanvas);
</script>