import {
Component, OnInit, Output, EventEmitter,
Input, ContentChildren, QueryList, ElementRef,
HostListener, AfterViewInit, Renderer2
} from '@angular/core';
import { UiCarouselItemComponent } from './ui-carousel-item.component';
import { UiCarouselColorConfig } from '../color-config.class';
@Component({
// tslint:disable-next-line:component-selector
selector: 'cre-carousel',
template: `
`,
styles: [`
:host {
display: block;
overflow: hidden;
position: relative;
}
`],
})
export class UiCarouselComponent implements OnInit, AfterViewInit {
@Input() height: string;
@Input() width = '100%';
@Input() speed: number;
@Input() autoPlay = true;
@Input() autoPlaySpeed: number;
@Input() infinite = true;
@Input() fade = false;
@Input() isDotsVisible = true;
@Input() isArrowsVisible = true;
@Input() isPrintButtonVisible = false;
@Input() colorConfig = new UiCarouselColorConfig();
@Output() onChange: EventEmitter = new EventEmitter();
@Output() printRequest: EventEmitter = new EventEmitter();
@ContentChildren(UiCarouselItemComponent) items: QueryList;
public currentItemIndex = 0;
public interval: any;
private _width: number;
private firstItemIndex: number; // the visual index of item and not necessary the index in the DOM
private lastItemIndex: number; // ..
private isSliding: boolean;
constructor(private el: ElementRef, private renderer2: Renderer2) { }
ngOnInit() {
this.speed = this.speed || 500;
this.autoPlaySpeed = this.autoPlaySpeed || 1500;
if (this.autoPlay) {
this.autoPlayFunction(true);
}
}
ngAfterViewInit() {
if (!this.height) {
let highest = 0;
this.items.forEach(itemELement => {
if (itemELement.el.nativeElement.offsetHeight > highest) {
highest = itemELement.el.nativeElement.offsetHeight;
}
});
this.height = `${highest}px`;
} else {
this.items.forEach(itemELement => {
itemELement.el.nativeElement.style.overflowY = 'auto';
});
}
this.items.forEach(itemELement => {
itemELement.el.nativeElement.style.height = this.height;
});
this.el.nativeElement.style.height = this.height;
this.el.nativeElement.style.width = this.width;
if (this.items && this.items.length > 0) {
this.onChange.emit(0);
this._width = this.items.first.el.nativeElement.offsetWidth;
}
this.firstItemIndex = 0;
this.lastItemIndex = this.items.length - 1;
if (!this.fade) {
this.items.toArray().forEach((item, itemIndex) => {
item.speed = this.speed;
item.position = this._width * itemIndex;
item.currentPosition = item.position;
item.disableTransition();
item.moveTo(item.position);
});
} else {
this.items.forEach((item, index) => {
item.zIndex = this.items.length - index;
item.setzIndex(item.zIndex);
});
}
setTimeout(() => {
this.items.forEach(item => {
item.colorConfig = this.colorConfig;
});
}, 50);
}
onPrintClick() {
const currentEl = this.items.toArray()[this.currentItemIndex].el;
this.printRequest.emit(currentEl);
}
next() {
this.slideRight();
}
prev() {
this.slideLeft();
}
goTo(index: number) {
if (!this.fade) {
this.slideTo(index);
} else {
this.fadeTo(index);
}
}
rotateRightTo(index: number) {
while (index !== this.lastItemIndex) {
this.rotateRight();
}
}
rotateLeftTo(index: number) {
while (index !== this.firstItemIndex) {
this.rotateLeft();
}
}
slideTo(index: number) {
this.onChange.emit((index + this.items.length) % this.items.length);
const steps = this.currentItemIndex - index;
if (this.infinite) {
if (steps > 0) {
this.rotateRightTo(this.currentItemIndex);
} else if (steps < 0) {
this.rotateLeftTo(this.currentItemIndex);
}
}
setTimeout(() => {
this.enableTransition();
this.items.forEach((item, i) => {
item.position += this._width * (steps);
item.currentPosition = item.position;
item.moveTo(item.position);
});
this.currentItemIndex = (index + this.items.length) % this.items.length;
}, 50);
}
slideLeft() {
if (!this.isSliding) {
this.isSliding = true;
if (!this.infinite) {
if (this.currentItemIndex === 0) {
this.slideToPrevPosition();
return;
}
}
this.slideTo(this.currentItemIndex - 1);
setTimeout(() => {
this.isSliding = false;
}, this.speed);
}
}
slideRight() {
if (!this.isSliding) {
this.isSliding = true;
if (!this.infinite) {
if (this.currentItemIndex === this.items.length - 1) {
this.slideToPrevPosition();
return;
}
}
this.slideTo(this.currentItemIndex + 1);
setTimeout(() => {
this.isSliding = false;
}, this.speed);
}
}
slideToPrevPosition() {
this.enableTransition();
this.items.forEach(item => {
item.currentPosition = item.position;
item.moveTo(item.position);
});
}
disableTransition() {
this.items.forEach((item, index) => {
item.disableTransition();
});
}
enableTransition() {
this.items.forEach((item, index) => {
item.enableTransition();
});
}
getItemByIndex(index: number) {
return this.items.find((item, i) => {
return i === index;
});
}
getIndexByItem(item: UiCarouselItemComponent) {
return this.items.toArray().indexOf(item);
}
rotateRightNTimes(n: number) {
for (let i = 0; i < n; i++) {
this.rotateRight();
}
}
rotateLeftNTimes(n: number) {
for (let i = 0; i < n; i++) {
this.rotateLeft();
}
}
rotateRight() {
const firstItemRef = this.getItemByIndex(this.firstItemIndex);
const lastItemRef = this.getItemByIndex(this.lastItemIndex);
if (!this.fade) {
lastItemRef.position = firstItemRef.position - this._width;
lastItemRef.currentPosition = lastItemRef.position;
lastItemRef.disableTransition();
lastItemRef.moveTo(lastItemRef.position);
this.firstItemIndex = this.lastItemIndex;
this.lastItemIndex = (this.lastItemIndex - 1 + this.items.length) % this.items.length;
}
}
rotateLeft() {
const firstItemRef = this.getItemByIndex(this.firstItemIndex);
const lastItemRef = this.getItemByIndex(this.lastItemIndex);
firstItemRef.position = lastItemRef.position + this._width;
firstItemRef.currentPosition = firstItemRef.position;
firstItemRef.disableTransition();
firstItemRef.moveTo(firstItemRef.position);
this.lastItemIndex = this.firstItemIndex;
this.firstItemIndex = (this.lastItemIndex + 1) % this.items.length;
}
fadeTo(index: number) {
this.onChange.emit(index);
const firstItem = this.getItemByIndex(this.currentItemIndex);
const targetItem = this.getItemByIndex(index);
const highestZIndex = this.items.length;
targetItem.zIndex = firstItem.zIndex + 1;
targetItem.setzIndex(targetItem.zIndex);
targetItem.disableTransition();
targetItem.fadeIn(this.speed);
this.currentItemIndex = index;
}
fadeRight() {
const newIndex = (this.currentItemIndex + 1) % this.items.length;
this.fadeTo(newIndex);
this.currentItemIndex = newIndex;
}
fadeLeft() {
const newIndex = (this.currentItemIndex - 1 + this.items.length) % this.items.length;
this.fadeTo(newIndex);
this.currentItemIndex = newIndex;
}
// is item first visually and not necessary first in the dom (QueryList)
isItemFirst(index: number) {
return this.firstItemIndex === index;
}
// is item last visually and not necessary last in the dom (QueryList)
isItemLast(index: number) {
return this.lastItemIndex === index;
}
@HostListener('window:resize', ['$event'])
onResize(event: any) {
this.rePosition();
}
rePosition() {
const items = this.items.toArray();
if (this.items && this.items.length > 0) {
this._width = this.items.first.el.nativeElement.offsetWidth;
}
items.sort((item1, item2) => {
if (item1.position > item2.position) {
return 1;
} else if (item1.position < item2.position) {
return -1;
} else {
return 0;
}
});
const currentItem = this.getItemByIndex(this.currentItemIndex);
const currentItemIndex = items.indexOf(currentItem);
for (let i = currentItemIndex; i < items.length + currentItemIndex; i++) {
const item = items[(i + items.length) % items.length];
item.position = ((i + items.length) % items.length - currentItemIndex) * this._width;
item.disableTransition();
item.moveTo(item.position);
}
}
autoPlayFunction(shouldAutoPlay: boolean) {
if (this.autoPlay) {
if (shouldAutoPlay) {
this.interval = setInterval(() => {
this.next();
}, this.autoPlaySpeed);
} else {
clearInterval(this.interval);
}
}
}
}