|
|
@ -2,6 +2,7 @@ import { animate, keyframes, state, style, transition, trigger } from '@angular/
|
|
|
|
import { NgStyle } from '@angular/common';
|
|
|
|
import { NgStyle } from '@angular/common';
|
|
|
|
import { AfterViewInit, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, TemplateRef, ViewChild, ViewChildren } from '@angular/core';
|
|
|
|
import { AfterViewInit, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, TemplateRef, ViewChild, ViewChildren } from '@angular/core';
|
|
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
|
|
|
|
|
|
import { AngularResizeEventModule, ResizedEvent } from 'angular-resize-event';
|
|
|
|
import { Subject, debounceTime } from 'rxjs';
|
|
|
|
import { Subject, debounceTime } from 'rxjs';
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
@Component({
|
|
|
@ -10,21 +11,22 @@ import { Subject, debounceTime } from 'rxjs';
|
|
|
|
styleUrls: ['./carousel.component.scss'],
|
|
|
|
styleUrls: ['./carousel.component.scss'],
|
|
|
|
standalone: true,
|
|
|
|
standalone: true,
|
|
|
|
imports: [
|
|
|
|
imports: [
|
|
|
|
BrowserModule
|
|
|
|
BrowserModule,
|
|
|
|
|
|
|
|
AngularResizeEventModule
|
|
|
|
],
|
|
|
|
],
|
|
|
|
animations: [
|
|
|
|
animations: [
|
|
|
|
trigger('direction', [
|
|
|
|
trigger('direction', [
|
|
|
|
|
|
|
|
|
|
|
|
state('vertical', style({})),
|
|
|
|
state('vertical', style({})),
|
|
|
|
state('horizontal', style({})),
|
|
|
|
state('horizontal', style({})),
|
|
|
|
|
|
|
|
|
|
|
|
state('hidden', style({
|
|
|
|
state('hidden', style({
|
|
|
|
opacity: 0,
|
|
|
|
opacity: 0,
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
state('unhidden', style({
|
|
|
|
state('unhidden', style({
|
|
|
|
opacity: 1,
|
|
|
|
opacity: 1,
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
|
|
transition('* => hidden', animate(`{{directionTime}}ms`)),
|
|
|
|
transition('* => hidden', animate(`{{directionTime}}ms`)),
|
|
|
|
transition('hidden => unhidden', animate(`{{directionTime}}ms`)),
|
|
|
|
transition('hidden => unhidden', animate(`{{directionTime}}ms`)),
|
|
|
|
transition('unhidden => *', animate('10ms')),
|
|
|
|
transition('unhidden => *', animate('10ms')),
|
|
|
@ -32,6 +34,7 @@ import { Subject, debounceTime } from 'rxjs';
|
|
|
|
]
|
|
|
|
]
|
|
|
|
})
|
|
|
|
})
|
|
|
|
export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
|
|
|
|
|
|
|
|
@Output() afterInitSelf: EventEmitter<CarouselComponent<T>> = new EventEmitter<CarouselComponent<T>>();
|
|
|
|
@Output() afterInitSelf: EventEmitter<CarouselComponent<T>> = new EventEmitter<CarouselComponent<T>>();
|
|
|
|
@Output() changedIndex: EventEmitter<number> = new EventEmitter<number>();
|
|
|
|
@Output() changedIndex: EventEmitter<number> = new EventEmitter<number>();
|
|
|
|
@Input() slides?: T[];
|
|
|
|
@Input() slides?: T[];
|
|
|
@ -51,13 +54,15 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
directionTime: number = 0;
|
|
|
|
directionTime: number = 0;
|
|
|
|
@Input() numVisible: number = 1;
|
|
|
|
@Input() numVisible: number = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
containerDirectionLength: number = 0;
|
|
|
|
|
|
|
|
|
|
|
|
private debouncedOnchange: Subject<void> = new Subject<void>();
|
|
|
|
private debouncedOnchange: Subject<void> = new Subject<void>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(private cdr: ChangeDetectorRef) {
|
|
|
|
constructor(private cdr: ChangeDetectorRef) {
|
|
|
|
this.visibleSlides = [];
|
|
|
|
this.visibleSlides = [];
|
|
|
|
this.debouncedOnchange.pipe(debounceTime(500)).subscribe(() => this.realOnChange());
|
|
|
|
this.debouncedOnchange.pipe(debounceTime(500)).subscribe(() => this.realOnChange());
|
|
|
|
if(this.initIndex) {
|
|
|
|
if (this.initIndex) {
|
|
|
|
this.current = this.initIndex;
|
|
|
|
this.current = this.initIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -115,7 +120,7 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
initialize() {
|
|
|
|
initialize() {
|
|
|
|
for(let i = 0; i <= this.numExtraNext() && i < this.slides!.length; i++) {
|
|
|
|
for (let i = 0; i <= this.numExtraNext() && i < this.slides!.length; i++) {
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
index: i,
|
|
|
|
index: i,
|
|
|
|
hasBeenVisible: false,
|
|
|
|
hasBeenVisible: false,
|
|
|
@ -131,7 +136,7 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
setIndex(slideIndex: number) {
|
|
|
|
setIndex(slideIndex: number) {
|
|
|
|
this.current = slideIndex;
|
|
|
|
this.current = slideIndex;
|
|
|
|
|
|
|
|
|
|
|
|
for(let i = Math.max(-this.numExtraPrev(), 0); i <= this.numExtraNext(); i++) {
|
|
|
|
for (let i = Math.max(-this.numExtraPrev(), 0); i <= Math.min(this.numExtraNext(), this.slides!.length - 1); i++) {
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
index: this.current + i,
|
|
|
|
index: this.current + i,
|
|
|
|
hasBeenVisible: false,
|
|
|
|
hasBeenVisible: false,
|
|
|
@ -146,9 +151,9 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
this.increasing = true;
|
|
|
|
this.increasing = true;
|
|
|
|
if (this.slides && this.current + 1 < this.slides?.length) {
|
|
|
|
if (this.slides && this.current + 1 < this.slides?.length) {
|
|
|
|
this.current += 1;
|
|
|
|
this.current += 1;
|
|
|
|
this.changedIndex.emit(this.current);
|
|
|
|
this.changedIndex.emit(this.current);
|
|
|
|
if (this.current + this.numExtraNext() < this.slides.length) {
|
|
|
|
if (this.current + this.numExtraNext() < this.slides.length) {
|
|
|
|
if (!this.visibleSlides?.find(e => e.index == this.current + this.numExtraNext() )) {
|
|
|
|
if (!this.visibleSlides?.find(e => e.index == this.current + this.numExtraNext())) {
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
this.visibleSlides?.push({
|
|
|
|
index: this.current + this.numExtraNext(),
|
|
|
|
index: this.current + this.numExtraNext(),
|
|
|
|
hasBeenVisible: false,
|
|
|
|
hasBeenVisible: false,
|
|
|
@ -164,7 +169,7 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
this.increasing = false;
|
|
|
|
this.increasing = false;
|
|
|
|
if (this.current - 1 >= 0) {
|
|
|
|
if (this.current - 1 >= 0) {
|
|
|
|
this.current -= 1;
|
|
|
|
this.current -= 1;
|
|
|
|
this.changedIndex.emit(this.current);
|
|
|
|
this.changedIndex.emit(this.current);
|
|
|
|
|
|
|
|
|
|
|
|
if (this.current - this.numExtraPrev() >= 0) {
|
|
|
|
if (this.current - this.numExtraPrev() >= 0) {
|
|
|
|
if (!this.visibleSlides?.find(e => e.index == this.current - this.numExtraPrev())) {
|
|
|
|
if (!this.visibleSlides?.find(e => e.index == this.current - this.numExtraPrev())) {
|
|
|
@ -201,17 +206,21 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
|
|
|
|
|
|
|
|
translation() {
|
|
|
|
translation() {
|
|
|
|
let num = (this.current - this.numExtraNext() - (this.numVisible % 2 == 0 ? 1 : 0)) * (-1 / this.numVisible) * 100;
|
|
|
|
let num = (this.current - this.numExtraNext() - (this.numVisible % 2 == 0 ? 1 : 0)) * (-1 / this.numVisible) * 100;
|
|
|
|
|
|
|
|
const step = this.containerDirectionLength / this.numVisible;
|
|
|
|
|
|
|
|
const pos = (this.current - this.numExtraNext() - (this.numVisible % 2 == 0 ? 1 : 0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const offset = pos * -step;
|
|
|
|
if (this.vertical) {
|
|
|
|
if (this.vertical) {
|
|
|
|
return `0 ${num}%`
|
|
|
|
return `0 ${offset}px`
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return `${num}% 0`
|
|
|
|
return `${offset}px 0`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
templateValue() {
|
|
|
|
templateValue() {
|
|
|
|
const len = this.slides?.length;
|
|
|
|
const len = this.slides?.length;
|
|
|
|
return `repeat(${len}, minmax(calc(100% / ${this.numVisible}), 1fr))`;
|
|
|
|
return `repeat(${len}, ${this.containerDirectionLength / this.numVisible}px)`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
style() {
|
|
|
|
style() {
|
|
|
@ -222,7 +231,7 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
if (this.vertical) {
|
|
|
|
if (this.vertical) {
|
|
|
|
style['grid-template-rows'] = this.templateValue();
|
|
|
|
style['grid-template-rows'] = this.templateValue();
|
|
|
|
style['grid-auto-flow'] = 'column';
|
|
|
|
style['grid-auto-flow'] = 'column';
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
style['grid-template-columns'] = this.templateValue();
|
|
|
|
style['grid-template-columns'] = this.templateValue();
|
|
|
|
style['grid-auto-flow'] = 'row';
|
|
|
|
style['grid-auto-flow'] = 'row';
|
|
|
@ -255,6 +264,14 @@ export class CarouselComponent<T> implements OnInit, AfterViewInit {
|
|
|
|
this.animation = 'hidden';
|
|
|
|
this.animation = 'hidden';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
carouselResize(event: ResizedEvent) {
|
|
|
|
|
|
|
|
if (this.vertical) {
|
|
|
|
|
|
|
|
this.containerDirectionLength = event.newRect.height;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.containerDirectionLength = event.newRect.width;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface IntersectingSlide {
|
|
|
|
interface IntersectingSlide {
|
|
|
|